3 * Copyright (c) 2011 - 2014, 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 EFI_HANDLE mImageHandle
;
20 extern BDS_LOAD_OPTION_SUPPORT
*BdsLoadOptionSupportList
;
25 OUT BDS_SUPPORTED_DEVICE
** SupportedBootDevice
29 LIST_ENTRY SupportedDeviceList
;
30 UINTN SupportedDeviceCount
;
32 UINTN SupportedDeviceSelected
;
36 // List the Boot Devices supported
39 // Start all the drivers first
40 BdsConnectAllDrivers ();
42 // List the supported devices
43 Status
= BootDeviceListSupportedInit (&SupportedDeviceList
);
44 ASSERT_EFI_ERROR(Status
);
46 SupportedDeviceCount
= 0;
47 for (Entry
= GetFirstNode (&SupportedDeviceList
);
48 !IsNull (&SupportedDeviceList
,Entry
);
49 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
52 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
53 Print(L
"[%d] %s\n",SupportedDeviceCount
+1,(*SupportedBootDevice
)->Description
);
56 CHAR16
* DevicePathTxt
;
57 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
59 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
60 ASSERT_EFI_ERROR(Status
);
61 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText ((*SupportedBootDevice
)->DevicePathProtocol
,TRUE
,TRUE
);
63 Print(L
"\t- %s\n",DevicePathTxt
);
65 FreePool(DevicePathTxt
);
68 SupportedDeviceCount
++;
71 if (SupportedDeviceCount
== 0) {
72 Print(L
"There is no supported device.\n");
78 // Select the Boot Device
80 SupportedDeviceSelected
= 0;
81 while (SupportedDeviceSelected
== 0) {
82 Print(L
"Select the Boot Device: ");
83 Status
= GetHIInputInteger (&SupportedDeviceSelected
);
84 if (EFI_ERROR(Status
)) {
87 } else if ((SupportedDeviceSelected
== 0) || (SupportedDeviceSelected
> SupportedDeviceCount
)) {
88 Print(L
"Invalid input (max %d)\n",SupportedDeviceCount
);
89 SupportedDeviceSelected
= 0;
94 // Get the Device Path for the selected boot device
97 for (Entry
= GetFirstNode (&SupportedDeviceList
);
98 !IsNull (&SupportedDeviceList
,Entry
);
99 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
102 if (Index
== SupportedDeviceSelected
) {
103 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
110 BootDeviceListSupportedFree (&SupportedDeviceList
, *SupportedBootDevice
);
115 BootMenuAddBootOption (
116 IN LIST_ENTRY
*BootOptionsList
120 BDS_SUPPORTED_DEVICE
* SupportedBootDevice
;
121 ARM_BDS_LOADER_ARGUMENTS
* BootArguments
;
122 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
123 CHAR8 AsciiCmdLine
[BOOT_DEVICE_OPTION_MAX
];
124 CHAR16 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
126 ARM_BDS_LOADER_TYPE BootType
;
127 BDS_LOAD_OPTION_ENTRY
*BdsLoadOptionEntry
;
128 EFI_DEVICE_PATH
*DevicePath
;
129 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNodes
;
130 EFI_DEVICE_PATH_PROTOCOL
*InitrdPathNodes
;
131 EFI_DEVICE_PATH_PROTOCOL
*InitrdPath
;
133 BOOLEAN InitrdSupport
;
136 UINTN OptionalDataSize
;
137 BOOLEAN RequestBootType
;
140 SupportedBootDevice
= NULL
;
142 // List the Boot Devices supported
143 Status
= SelectBootDevice (&SupportedBootDevice
);
144 if (EFI_ERROR(Status
)) {
145 Status
= EFI_ABORTED
;
149 // Create the specific device path node
150 RequestBootType
= TRUE
;
151 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"EFI Application or the kernel", &DevicePathNodes
, &RequestBootType
);
152 if (EFI_ERROR(Status
)) {
153 Status
= EFI_ABORTED
;
156 // Append the Device Path to the selected device path
157 DevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)DevicePathNodes
);
158 if (DevicePath
== NULL
) {
159 Status
= EFI_OUT_OF_RESOURCES
;
163 if (RequestBootType
) {
164 Status
= BootDeviceGetType (DevicePath
, &BootType
, &Attributes
);
165 if (EFI_ERROR(Status
)) {
166 Status
= EFI_ABORTED
;
170 BootType
= BDS_LOADER_EFI_APPLICATION
;
173 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
174 Print(L
"Add an initrd: ");
175 Status
= GetHIInputBoolean (&InitrdSupport
);
176 if (EFI_ERROR(Status
)) {
177 Status
= EFI_ABORTED
;
182 // Create the specific device path node
183 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"initrd", &InitrdPathNodes
, NULL
);
184 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
185 Status
= EFI_ABORTED
;
189 if (InitrdPathNodes
!= NULL
) {
190 // Append the Device Path to the selected device path
191 InitrdPath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)InitrdPathNodes
);
192 if (InitrdPath
== NULL
) {
193 Status
= EFI_OUT_OF_RESOURCES
;
203 Print(L
"Arguments to pass to the binary: ");
204 Status
= GetHIInputAscii (AsciiCmdLine
, BOOT_DEVICE_OPTION_MAX
);
205 if (EFI_ERROR(Status
)) {
206 Status
= EFI_ABORTED
;
207 goto FREE_DEVICE_PATH
;
210 CmdLineSize
= AsciiStrSize (AsciiCmdLine
);
211 InitrdSize
= GetDevicePathSize (InitrdPath
);
213 OptionalDataSize
= sizeof(ARM_BDS_LOADER_ARGUMENTS
) + CmdLineSize
+ InitrdSize
;
214 BootArguments
= (ARM_BDS_LOADER_ARGUMENTS
*)AllocatePool (OptionalDataSize
);
216 BootArguments
->LinuxArguments
.CmdLineSize
= CmdLineSize
;
217 BootArguments
->LinuxArguments
.InitrdSize
= InitrdSize
;
218 CopyMem ((VOID
*)(&BootArguments
->LinuxArguments
+ 1), AsciiCmdLine
, CmdLineSize
);
219 CopyMem ((VOID
*)((UINTN
)(&BootArguments
->LinuxArguments
+ 1) + CmdLineSize
), InitrdPath
, InitrdSize
);
221 OptionalData
= (UINT8
*)BootArguments
;
223 Print (L
"Arguments to pass to the EFI Application: ");
224 Status
= GetHIInputStr (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
225 if (EFI_ERROR (Status
)) {
226 Status
= EFI_ABORTED
;
230 OptionalData
= (UINT8
*)CmdLine
;
231 OptionalDataSize
= StrSize (CmdLine
);
234 Print(L
"Description for this new Entry: ");
235 Status
= GetHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
236 if (EFI_ERROR(Status
)) {
237 Status
= EFI_ABORTED
;
238 goto FREE_DEVICE_PATH
;
242 BdsLoadOptionEntry
= (BDS_LOAD_OPTION_ENTRY
*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY
));
243 Status
= BootOptionCreate (Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
, &BdsLoadOptionEntry
->BdsLoadOption
);
244 if (!EFI_ERROR(Status
)) {
245 InsertTailList (BootOptionsList
, &BdsLoadOptionEntry
->Link
);
249 FreePool (DevicePath
);
252 if (Status
== EFI_ABORTED
) {
255 FreePool(SupportedBootDevice
);
261 BootMenuSelectBootOption (
262 IN LIST_ENTRY
* BootOptionsList
,
263 IN CONST CHAR16
* InputStatement
,
264 OUT BDS_LOAD_OPTION_ENTRY
** BdsLoadOptionEntry
269 BDS_LOAD_OPTION
* BdsLoadOption
;
270 UINTN BootOptionSelected
;
271 UINTN BootOptionCount
;
275 // Display the list of supported boot devices
277 for (Entry
= GetFirstNode (BootOptionsList
);
278 !IsNull (BootOptionsList
,Entry
);
279 Entry
= GetNextNode (BootOptionsList
, Entry
)
282 BdsLoadOption
= LOAD_OPTION_FROM_LINK(Entry
);
284 Print (L
"[%d] %s\n", (BootOptionCount
+ 1), BdsLoadOption
->Description
);
287 CHAR16
* DevicePathTxt
;
288 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
289 ARM_BDS_LOADER_TYPE LoaderType
;
290 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
292 Status
= gBS
->LocateProtocol(&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
293 ASSERT_EFI_ERROR(Status
);
294 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText(BdsLoadOption
->FilePathList
,TRUE
,TRUE
);
296 Print(L
"\t- %s\n",DevicePathTxt
);
297 OptionalData
= BdsLoadOption
->OptionalData
;
298 if (IS_ARM_BDS_BOOTENTRY (BdsLoadOption
)) {
299 LoaderType
= (ARM_BDS_LOADER_TYPE
)ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
300 if ((LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
301 Print (L
"\t- Arguments: %a\n",&OptionalData
->Arguments
.LinuxArguments
+ 1);
303 } else if (OptionalData
!= NULL
) {
304 if (IsPrintableString (OptionalData
, &IsUnicode
)) {
306 Print (L
"\t- Arguments: %s\n", OptionalData
);
308 AsciiPrint ("\t- Arguments: %a\n", OptionalData
);
313 FreePool(DevicePathTxt
);
319 // Check if a valid boot option(s) is found
320 if (BootOptionCount
== 0) {
321 if (StrCmp (InputStatement
, DELETE_BOOT_ENTRY
) == 0) {
322 Print (L
"Nothing to remove!\n");
323 } else if (StrCmp (InputStatement
, UPDATE_BOOT_ENTRY
) == 0) {
324 Print (L
"Couldn't find valid boot entries\n");
326 Print (L
"No supported Boot Entry.\n");
329 return EFI_NOT_FOUND
;
332 // Get the index of the boot device to delete
333 BootOptionSelected
= 0;
334 while (BootOptionSelected
== 0) {
335 Print(InputStatement
);
336 Status
= GetHIInputInteger (&BootOptionSelected
);
337 if (EFI_ERROR(Status
)) {
339 } else if ((BootOptionSelected
== 0) || (BootOptionSelected
> BootOptionCount
)) {
340 Print(L
"Invalid input (max %d)\n",BootOptionCount
);
341 BootOptionSelected
= 0;
345 // Get the structure of the Boot device to delete
347 for (Entry
= GetFirstNode (BootOptionsList
);
348 !IsNull (BootOptionsList
, Entry
);
349 Entry
= GetNextNode (BootOptionsList
,Entry
)
352 if (Index
== BootOptionSelected
) {
353 *BdsLoadOptionEntry
= LOAD_OPTION_ENTRY_FROM_LINK(Entry
);
363 BootMenuRemoveBootOption (
364 IN LIST_ENTRY
*BootOptionsList
368 BDS_LOAD_OPTION_ENTRY
* BootOptionEntry
;
370 Status
= BootMenuSelectBootOption (BootOptionsList
, DELETE_BOOT_ENTRY
, &BootOptionEntry
);
371 if (EFI_ERROR(Status
)) {
375 // If the Boot Option was attached to a list remove it
376 if (!IsListEmpty (&BootOptionEntry
->Link
)) {
377 // Remove the entry from the list
378 RemoveEntryList (&BootOptionEntry
->Link
);
381 // Delete the BDS Load option structures
382 BootOptionDelete (BootOptionEntry
->BdsLoadOption
);
388 BootMenuUpdateBootOption (
389 IN LIST_ENTRY
*BootOptionsList
393 BDS_LOAD_OPTION_ENTRY
*BootOptionEntry
;
394 BDS_LOAD_OPTION
*BootOption
;
395 BDS_LOAD_OPTION_SUPPORT
* DeviceSupport
;
396 ARM_BDS_LOADER_ARGUMENTS
* BootArguments
;
397 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
398 CHAR8 CmdLine
[BOOT_DEVICE_OPTION_MAX
];
399 CHAR16 UnicodeCmdLine
[BOOT_DEVICE_OPTION_MAX
];
400 EFI_DEVICE_PATH
*DevicePath
;
401 EFI_DEVICE_PATH
*TempInitrdPath
;
402 ARM_BDS_LOADER_TYPE BootType
;
403 ARM_BDS_LOADER_OPTIONAL_DATA
* LoaderOptionalData
;
404 ARM_BDS_LINUX_ARGUMENTS
* LinuxArguments
;
405 EFI_DEVICE_PATH
*InitrdPathNodes
;
406 EFI_DEVICE_PATH
*InitrdPath
;
409 BOOLEAN InitrdSupport
;
411 UINTN OptionalDataSize
;
412 BOOLEAN RequestBootType
;
416 Status
= BootMenuSelectBootOption (BootOptionsList
, UPDATE_BOOT_ENTRY
, &BootOptionEntry
);
417 if (EFI_ERROR(Status
)) {
420 BootOption
= BootOptionEntry
->BdsLoadOption
;
422 // Get the device support for this Boot Option
423 Status
= BootDeviceGetDeviceSupport (BootOption
->FilePathList
, &DeviceSupport
);
424 if (EFI_ERROR(Status
)) {
425 Print(L
"Not possible to retrieve the supported device for the update\n");
426 return EFI_UNSUPPORTED
;
429 RequestBootType
= TRUE
;
430 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
->FilePathList
, L
"EFI Application or the kernel", &DevicePath
, &RequestBootType
);
431 if (EFI_ERROR(Status
)) {
432 Status
= EFI_ABORTED
;
436 if (RequestBootType
) {
437 Status
= BootDeviceGetType (DevicePath
, &BootType
, &BootOption
->Attributes
);
438 if (EFI_ERROR(Status
)) {
439 Status
= EFI_ABORTED
;
444 LoaderOptionalData
= BootOption
->OptionalData
;
445 if (LoaderOptionalData
!= NULL
) {
446 BootType
= (ARM_BDS_LOADER_TYPE
)ReadUnaligned32 ((UINT32
*)(&LoaderOptionalData
->Header
.LoaderType
));
448 BootType
= BDS_LOADER_EFI_APPLICATION
;
451 if ((BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (BootType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
452 LinuxArguments
= &LoaderOptionalData
->Arguments
.LinuxArguments
;
454 CmdLineSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->CmdLineSize
);
456 InitrdSize
= ReadUnaligned16 ((CONST UINT16
*)&LinuxArguments
->InitrdSize
);
457 if (InitrdSize
> 0) {
458 Print(L
"Keep the initrd: ");
460 Print(L
"Add an initrd: ");
462 Status
= GetHIInputBoolean (&InitrdSupport
);
463 if (EFI_ERROR(Status
)) {
464 Status
= EFI_ABORTED
;
469 if (InitrdSize
> 0) {
470 // Case we update the initrd device path
471 Status
= DeviceSupport
->UpdateDevicePathNode ((EFI_DEVICE_PATH
*)((UINTN
)(LinuxArguments
+ 1) + CmdLineSize
), L
"initrd", &InitrdPath
, NULL
);
472 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
473 Status
= EFI_ABORTED
;
476 InitrdSize
= GetDevicePathSize (InitrdPath
);
478 // Case we create the initrd device path
480 Status
= DeviceSupport
->CreateDevicePathNode (L
"initrd", &InitrdPathNodes
, NULL
);
481 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
482 Status
= EFI_ABORTED
;
486 if (InitrdPathNodes
!= NULL
) {
487 // Duplicate Linux kernel Device Path
488 TempInitrdPath
= DuplicateDevicePath (BootOption
->FilePathList
);
489 // Replace Linux kernel Node by EndNode
490 SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath
));
491 // Append the Device Path to the selected device path
492 InitrdPath
= AppendDevicePath (TempInitrdPath
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)InitrdPathNodes
);
493 FreePool (TempInitrdPath
);
494 if (InitrdPath
== NULL
) {
495 Status
= EFI_OUT_OF_RESOURCES
;
498 InitrdSize
= GetDevicePathSize (InitrdPath
);
507 Print(L
"Arguments to pass to the binary: ");
508 if (CmdLineSize
> 0) {
509 AsciiStrnCpy(CmdLine
, (CONST CHAR8
*)(LinuxArguments
+ 1), CmdLineSize
);
513 Status
= EditHIInputAscii (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
514 if (EFI_ERROR(Status
)) {
515 Status
= EFI_ABORTED
;
516 goto FREE_DEVICE_PATH
;
519 CmdLineSize
= AsciiStrSize (CmdLine
);
521 OptionalDataSize
= sizeof(ARM_BDS_LOADER_ARGUMENTS
) + CmdLineSize
+ InitrdSize
;
522 BootArguments
= (ARM_BDS_LOADER_ARGUMENTS
*)AllocatePool (OptionalDataSize
);
523 BootArguments
->LinuxArguments
.CmdLineSize
= CmdLineSize
;
524 BootArguments
->LinuxArguments
.InitrdSize
= InitrdSize
;
525 CopyMem (&BootArguments
->LinuxArguments
+ 1, CmdLine
, CmdLineSize
);
526 CopyMem ((VOID
*)((UINTN
)(&BootArguments
->LinuxArguments
+ 1) + CmdLineSize
), InitrdPath
, InitrdSize
);
528 OptionalData
= (UINT8
*)BootArguments
;
530 Print (L
"Arguments to pass to the EFI Application: ");
532 if (BootOption
->OptionalDataSize
> 0) {
533 IsPrintable
= IsPrintableString (BootOption
->OptionalData
, &IsUnicode
);
536 StrnCpy (UnicodeCmdLine
, BootOption
->OptionalData
, BootOption
->OptionalDataSize
/ 2);
538 AsciiStrnCpy (CmdLine
, BootOption
->OptionalData
, BootOption
->OptionalDataSize
);
542 UnicodeCmdLine
[0] = L
'\0';
547 // We do not request arguments for OptionalData that cannot be printed
550 Status
= EditHIInputStr (UnicodeCmdLine
, BOOT_DEVICE_OPTION_MAX
);
551 if (EFI_ERROR (Status
)) {
552 Status
= EFI_ABORTED
;
553 goto FREE_DEVICE_PATH
;
556 OptionalData
= (UINT8
*)UnicodeCmdLine
;
557 OptionalDataSize
= StrSize (UnicodeCmdLine
);
559 Status
= EditHIInputAscii (CmdLine
, BOOT_DEVICE_OPTION_MAX
);
560 if (EFI_ERROR (Status
)) {
561 Status
= EFI_ABORTED
;
562 goto FREE_DEVICE_PATH
;
565 OptionalData
= (UINT8
*)CmdLine
;
566 OptionalDataSize
= AsciiStrSize (CmdLine
);
569 // We keep the former OptionalData
570 OptionalData
= BootOption
->OptionalData
;
571 OptionalDataSize
= BootOption
->OptionalDataSize
;
575 Print(L
"Description for this new Entry: ");
576 StrnCpy (BootDescription
, BootOption
->Description
, BOOT_DEVICE_DESCRIPTION_MAX
);
577 Status
= EditHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
578 if (EFI_ERROR(Status
)) {
579 Status
= EFI_ABORTED
;
580 goto FREE_DEVICE_PATH
;
584 Status
= BootOptionUpdate (BootOption
, BootOption
->Attributes
, BootDescription
, DevicePath
, BootType
, OptionalData
, OptionalDataSize
);
587 FreePool (DevicePath
);
590 if (Status
== EFI_ABORTED
) {
598 IN LIST_ENTRY
*BootOptionsList
602 UINTN FdtDevicePathSize
;
603 BDS_SUPPORTED_DEVICE
*SupportedBootDevice
;
604 EFI_DEVICE_PATH_PROTOCOL
*FdtDevicePathNodes
;
605 EFI_DEVICE_PATH_PROTOCOL
*FdtDevicePath
;
607 Status
= SelectBootDevice (&SupportedBootDevice
);
608 if (EFI_ERROR(Status
)) {
609 Status
= EFI_ABORTED
;
613 // Create the specific device path node
614 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (L
"FDT blob", &FdtDevicePathNodes
, NULL
);
615 if (EFI_ERROR(Status
)) {
616 Status
= EFI_ABORTED
;
620 if (FdtDevicePathNodes
!= NULL
) {
621 // Append the Device Path node to the select device path
622 FdtDevicePath
= AppendDevicePath (SupportedBootDevice
->DevicePathProtocol
, FdtDevicePathNodes
);
623 FdtDevicePathSize
= GetDevicePathSize (FdtDevicePath
);
624 Status
= gRT
->SetVariable (
626 &gArmGlobalVariableGuid
,
627 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
631 ASSERT_EFI_ERROR(Status
);
635 &gArmGlobalVariableGuid
,
636 EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
,
640 ASSERT_EFI_ERROR(Status
);
644 if (Status
== EFI_ABORTED
) {
647 FreePool(SupportedBootDevice
);
654 Ask for the boot timeout in seconds and if the input succeeds assign the
655 input value to the UEFI global variable "Timeout". This function is called
656 when the user selects the "Set Boot Timeout" of the boot manager menu.
658 @param[in] BootOptionsList List of the boot devices, not used here
660 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard
661 input and assigned to the UEFI "Timeout" global
663 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global
664 variable "Timeout" has failed.
668 BootMenuSetBootTimeout (
669 IN LIST_ENTRY
*BootOptionsList
676 Print (L
"Timeout duration (in seconds): ");
677 Status
= GetHIInputInteger (&Input
);
678 if (EFI_ERROR (Status
)) {
684 Status
= gRT
->SetVariable (
686 &gEfiGlobalVariableGuid
,
687 EFI_VARIABLE_NON_VOLATILE
|
688 EFI_VARIABLE_BOOTSERVICE_ACCESS
|
689 EFI_VARIABLE_RUNTIME_ACCESS
,
693 ASSERT_EFI_ERROR (Status
);
699 struct BOOT_MANAGER_ENTRY
{
700 CONST CHAR16
* Description
;
701 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
702 } BootManagerEntries
[] = {
703 { L
"Add Boot Device Entry", BootMenuAddBootOption
},
704 { L
"Update Boot Device Entry", BootMenuUpdateBootOption
},
705 { L
"Remove Boot Device Entry", BootMenuRemoveBootOption
},
706 { L
"Update FDT path", UpdateFdtPath
},
707 { L
"Set Boot Timeout", BootMenuSetBootTimeout
},
712 IN LIST_ENTRY
*BootOptionsList
716 UINTN OptionSelected
;
717 UINTN BootManagerEntryCount
;
720 BootManagerEntryCount
= sizeof(BootManagerEntries
) / sizeof(struct BOOT_MANAGER_ENTRY
);
723 // Display Boot Manager menu
724 for (Index
= 0; Index
< BootManagerEntryCount
; Index
++) {
725 Print(L
"[%d] %s\n",Index
+1,BootManagerEntries
[Index
]);
727 Print(L
"[%d] Return to main menu\n",Index
+1);
729 // Select which entry to call
731 Status
= GetHIInputInteger (&OptionSelected
);
732 if (EFI_ERROR(Status
) || (OptionSelected
== (BootManagerEntryCount
+1))) {
733 if (EFI_ERROR(Status
)) {
737 } else if ((OptionSelected
> 0) && (OptionSelected
<= BootManagerEntryCount
)) {
738 BootManagerEntries
[OptionSelected
-1].Callback (BootOptionsList
);
741 // Should never go here
746 IN LIST_ENTRY
*BootOptionsList
752 Status
= BdsLoadApplication (mImageHandle
, L
"Shell", 0, NULL
);
753 if (Status
== EFI_NOT_FOUND
) {
754 Print (L
"Error: EFI Application not found.\n");
755 } else if (EFI_ERROR(Status
)) {
756 Print (L
"Error: Status Code: 0x%X\n",(UINT32
)Status
);
762 struct BOOT_MAIN_ENTRY
{
763 CONST CHAR16
* Description
;
764 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
765 } BootMainEntries
[] = {
766 { L
"Shell", BootShell
},
767 { L
"Boot Manager", BootMenuManager
},
776 LIST_ENTRY BootOptionsList
;
778 UINTN BootOptionCount
;
781 BDS_LOAD_OPTION
* BootOption
;
782 UINTN BootOptionSelected
;
784 UINTN BootMainEntryCount
;
788 BootMainEntryCount
= sizeof(BootMainEntries
) / sizeof(struct BOOT_MAIN_ENTRY
);
792 BootOptionList (&BootOptionsList
);
796 // Display the Boot options
797 for (Entry
= GetFirstNode (&BootOptionsList
);
798 !IsNull (&BootOptionsList
,Entry
);
799 Entry
= GetNextNode (&BootOptionsList
,Entry
)
802 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
804 Print(L
"[%d] %s\n", OptionCount
, BootOption
->Description
);
807 CHAR16
* DevicePathTxt
;
808 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
809 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
811 ARM_BDS_LOADER_TYPE LoaderType
;
813 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
814 if (EFI_ERROR(Status
)) {
815 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
816 DEBUG((EFI_D_ERROR
,"Error: Bds requires DevicePathToTextProtocol\n"));
819 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (BootOption
->FilePathList
, TRUE
, TRUE
);
821 Print(L
"\t- %s\n",DevicePathTxt
);
823 // If it is a supported BootEntry then print its details
824 if (IS_ARM_BDS_BOOTENTRY (BootOption
)) {
825 OptionalData
= BootOption
->OptionalData
;
826 LoaderType
= (ARM_BDS_LOADER_TYPE
)ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
827 if ((LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
828 if (ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.InitrdSize
) > 0) {
829 CmdLineSize
= ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.CmdLineSize
);
830 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (
831 GetAlignedDevicePath ((EFI_DEVICE_PATH
*)((UINTN
)(&OptionalData
->Arguments
.LinuxArguments
+ 1) + CmdLineSize
)), TRUE
, TRUE
);
832 Print(L
"\t- Initrd: %s\n", DevicePathTxt
);
834 if (ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.CmdLineSize
) > 0) {
835 Print(L
"\t- Arguments: %a\n", (&OptionalData
->Arguments
.LinuxArguments
+ 1));
839 switch (LoaderType
) {
840 case BDS_LOADER_EFI_APPLICATION
:
841 Print(L
"\t- LoaderType: EFI Application\n");
844 case BDS_LOADER_KERNEL_LINUX_ATAG
:
845 Print(L
"\t- LoaderType: Linux kernel with ATAG support\n");
848 case BDS_LOADER_KERNEL_LINUX_FDT
:
849 Print(L
"\t- LoaderType: Linux kernel with FDT support\n");
853 Print(L
"\t- LoaderType: Not recognized (%d)\n", LoaderType
);
855 } else if (BootOption
->OptionalData
!= NULL
) {
856 if (IsPrintableString (BootOption
->OptionalData
, &IsUnicode
)) {
858 Print (L
"\t- Arguments: %s\n", BootOption
->OptionalData
);
860 AsciiPrint ("\t- Arguments: %a\n", BootOption
->OptionalData
);
864 FreePool(DevicePathTxt
);
869 BootOptionCount
= OptionCount
-1;
871 // Display the hardcoded Boot entries
872 for (Index
= 0; Index
< BootMainEntryCount
; Index
++) {
873 Print(L
"[%d] %s\n",OptionCount
,BootMainEntries
[Index
]);
877 // Request the boot entry from the user
878 BootOptionSelected
= 0;
879 while (BootOptionSelected
== 0) {
881 Status
= GetHIInputInteger (&BootOptionSelected
);
882 if (EFI_ERROR(Status
) || (BootOptionSelected
== 0) || (BootOptionSelected
> OptionCount
)) {
883 Print(L
"Invalid input (max %d)\n",(OptionCount
-1));
884 BootOptionSelected
= 0;
888 // Start the selected entry
889 if (BootOptionSelected
> BootOptionCount
) {
890 // Start the hardcoded entry
891 Status
= BootMainEntries
[BootOptionSelected
- BootOptionCount
- 1].Callback (&BootOptionsList
);
893 // Find the selected entry from the Boot#### list
895 for (Entry
= GetFirstNode (&BootOptionsList
);
896 !IsNull (&BootOptionsList
,Entry
);
897 Entry
= GetNextNode (&BootOptionsList
,Entry
)
900 if (Index
== BootOptionSelected
) {
901 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
907 Status
= BootOptionStart (BootOption
);
910 // Should never go here