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), CmdLine
, 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
);
651 struct BOOT_MANAGER_ENTRY
{
652 CONST CHAR16
* Description
;
653 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
654 } BootManagerEntries
[] = {
655 { L
"Add Boot Device Entry", BootMenuAddBootOption
},
656 { L
"Update Boot Device Entry", BootMenuUpdateBootOption
},
657 { L
"Remove Boot Device Entry", BootMenuRemoveBootOption
},
658 { L
"Update FDT path", UpdateFdtPath
},
663 IN LIST_ENTRY
*BootOptionsList
667 UINTN OptionSelected
;
668 UINTN BootManagerEntryCount
;
671 BootManagerEntryCount
= sizeof(BootManagerEntries
) / sizeof(struct BOOT_MANAGER_ENTRY
);
674 // Display Boot Manager menu
675 for (Index
= 0; Index
< BootManagerEntryCount
; Index
++) {
676 Print(L
"[%d] %s\n",Index
+1,BootManagerEntries
[Index
]);
678 Print(L
"[%d] Return to main menu\n",Index
+1);
680 // Select which entry to call
682 Status
= GetHIInputInteger (&OptionSelected
);
683 if (EFI_ERROR(Status
) || (OptionSelected
== (BootManagerEntryCount
+1))) {
684 if (EFI_ERROR(Status
)) {
688 } else if ((OptionSelected
> 0) && (OptionSelected
<= BootManagerEntryCount
)) {
689 BootManagerEntries
[OptionSelected
-1].Callback (BootOptionsList
);
692 // Should never go here
697 IN LIST_ENTRY
*BootOptionsList
703 Status
= BdsLoadApplication (mImageHandle
, L
"Shell", 0, NULL
);
704 if (Status
== EFI_NOT_FOUND
) {
705 Print (L
"Error: EFI Application not found.\n");
706 } else if (EFI_ERROR(Status
)) {
707 Print (L
"Error: Status Code: 0x%X\n",(UINT32
)Status
);
713 struct BOOT_MAIN_ENTRY
{
714 CONST CHAR16
* Description
;
715 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
716 } BootMainEntries
[] = {
717 { L
"Shell", BootShell
},
718 { L
"Boot Manager", BootMenuManager
},
727 LIST_ENTRY BootOptionsList
;
729 UINTN BootOptionCount
;
732 BDS_LOAD_OPTION
* BootOption
;
733 UINTN BootOptionSelected
;
735 UINTN BootMainEntryCount
;
739 BootMainEntryCount
= sizeof(BootMainEntries
) / sizeof(struct BOOT_MAIN_ENTRY
);
743 BootOptionList (&BootOptionsList
);
747 // Display the Boot options
748 for (Entry
= GetFirstNode (&BootOptionsList
);
749 !IsNull (&BootOptionsList
,Entry
);
750 Entry
= GetNextNode (&BootOptionsList
,Entry
)
753 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
755 Print(L
"[%d] %s\n", OptionCount
, BootOption
->Description
);
758 CHAR16
* DevicePathTxt
;
759 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
760 ARM_BDS_LOADER_OPTIONAL_DATA
* OptionalData
;
762 ARM_BDS_LOADER_TYPE LoaderType
;
764 Status
= gBS
->LocateProtocol (&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
765 if (EFI_ERROR(Status
)) {
766 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
767 DEBUG((EFI_D_ERROR
,"Error: Bds requires DevicePathToTextProtocol\n"));
770 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (BootOption
->FilePathList
, TRUE
, TRUE
);
772 Print(L
"\t- %s\n",DevicePathTxt
);
774 // If it is a supported BootEntry then print its details
775 if (IS_ARM_BDS_BOOTENTRY (BootOption
)) {
776 OptionalData
= BootOption
->OptionalData
;
777 LoaderType
= (ARM_BDS_LOADER_TYPE
)ReadUnaligned32 ((CONST UINT32
*)&OptionalData
->Header
.LoaderType
);
778 if ((LoaderType
== BDS_LOADER_KERNEL_LINUX_ATAG
) || (LoaderType
== BDS_LOADER_KERNEL_LINUX_FDT
)) {
779 if (ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.InitrdSize
) > 0) {
780 CmdLineSize
= ReadUnaligned16 (&OptionalData
->Arguments
.LinuxArguments
.CmdLineSize
);
781 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText (
782 GetAlignedDevicePath ((EFI_DEVICE_PATH
*)((UINTN
)(&OptionalData
->Arguments
.LinuxArguments
+ 1) + CmdLineSize
)), TRUE
, TRUE
);
783 Print(L
"\t- Initrd: %s\n", DevicePathTxt
);
785 Print(L
"\t- Arguments: %a\n", (&OptionalData
->Arguments
.LinuxArguments
+ 1));
788 switch (LoaderType
) {
789 case BDS_LOADER_EFI_APPLICATION
:
790 Print(L
"\t- LoaderType: EFI Application\n");
793 case BDS_LOADER_KERNEL_LINUX_ATAG
:
794 Print(L
"\t- LoaderType: Linux kernel with ATAG support\n");
797 case BDS_LOADER_KERNEL_LINUX_FDT
:
798 Print(L
"\t- LoaderType: Linux kernel with FDT support\n");
802 Print(L
"\t- LoaderType: Not recognized (%d)\n", LoaderType
);
804 } else if (BootOption
->OptionalData
!= NULL
) {
805 if (IsPrintableString (BootOption
->OptionalData
, &IsUnicode
)) {
807 Print (L
"\t- Arguments: %s\n", BootOption
->OptionalData
);
809 AsciiPrint ("\t- Arguments: %a\n", BootOption
->OptionalData
);
813 FreePool(DevicePathTxt
);
818 BootOptionCount
= OptionCount
-1;
820 // Display the hardcoded Boot entries
821 for (Index
= 0; Index
< BootMainEntryCount
; Index
++) {
822 Print(L
"[%d] %s\n",OptionCount
,BootMainEntries
[Index
]);
826 // Request the boot entry from the user
827 BootOptionSelected
= 0;
828 while (BootOptionSelected
== 0) {
830 Status
= GetHIInputInteger (&BootOptionSelected
);
831 if (EFI_ERROR(Status
) || (BootOptionSelected
== 0) || (BootOptionSelected
> OptionCount
)) {
832 Print(L
"Invalid input (max %d)\n",(OptionCount
-1));
833 BootOptionSelected
= 0;
837 // Start the selected entry
838 if (BootOptionSelected
> BootOptionCount
) {
839 // Start the hardcoded entry
840 Status
= BootMainEntries
[BootOptionSelected
- BootOptionCount
- 1].Callback (&BootOptionsList
);
842 // Find the selected entry from the Boot#### list
844 for (Entry
= GetFirstNode (&BootOptionsList
);
845 !IsNull (&BootOptionsList
,Entry
);
846 Entry
= GetNextNode (&BootOptionsList
,Entry
)
849 if (Index
== BootOptionSelected
) {
850 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
856 Status
= BootOptionStart (BootOption
);
859 // Should never go here