3 * Copyright (c) 2011, 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 extern EFI_HANDLE mImageHandle
;
18 extern BDS_LOAD_OPTION_SUPPORT
*BdsLoadOptionSupportList
;
22 OUT BDS_SUPPORTED_DEVICE
** SupportedBootDevice
26 LIST_ENTRY SupportedDeviceList
;
27 UINTN SupportedDeviceCount
;
29 UINTN SupportedDeviceSelected
;
33 // List the Boot Devices supported
36 // Start all the drivers first
37 BdsConnectAllDrivers ();
39 // List the supported devices
40 Status
= BootDeviceListSupportedInit (&SupportedDeviceList
);
41 ASSERT_EFI_ERROR(Status
);
43 SupportedDeviceCount
= 0;
44 for (Entry
= GetFirstNode (&SupportedDeviceList
);
45 !IsNull (&SupportedDeviceList
,Entry
);
46 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
49 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
50 Print(L
"[%d] %s\n",SupportedDeviceCount
+1,(*SupportedBootDevice
)->Description
);
53 CHAR16
* DevicePathTxt
;
54 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
56 Status
= gBS
->LocateProtocol(&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
57 ASSERT_EFI_ERROR(Status
);
58 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText((*SupportedBootDevice
)->DevicePathProtocol
,TRUE
,TRUE
);
60 Print(L
"\t- %s\n",DevicePathTxt
);
62 FreePool(DevicePathTxt
);
65 SupportedDeviceCount
++;
68 if (SupportedDeviceCount
== 0) {
69 Print(L
"There is no supported device.\n");
75 // Select the Boot Device
77 SupportedDeviceSelected
= 0;
78 while (SupportedDeviceSelected
== 0) {
79 Print(L
"Select the Boot Device: ");
80 Status
= GetHIInputInteger (&SupportedDeviceSelected
);
81 if (EFI_ERROR(Status
)) {
84 } else if ((SupportedDeviceSelected
== 0) || (SupportedDeviceSelected
> SupportedDeviceCount
)) {
85 Print(L
"Invalid input (max %d)\n",SupportedDeviceSelected
);
86 SupportedDeviceSelected
= 0;
91 // Get the Device Path for the selected boot device
94 for (Entry
= GetFirstNode (&SupportedDeviceList
);
95 !IsNull (&SupportedDeviceList
,Entry
);
96 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
99 if (Index
== SupportedDeviceSelected
) {
100 *SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
107 BootDeviceListSupportedFree (&SupportedDeviceList
, *SupportedBootDevice
);
112 BootMenuAddBootOption (
113 IN LIST_ENTRY
*BootOptionsList
117 BDS_SUPPORTED_DEVICE
* SupportedBootDevice
;
118 BDS_LOADER_ARGUMENTS BootArguments
;
119 CHAR8 AsciiBootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
120 CHAR16
*BootDescription
;
122 BDS_LOADER_TYPE BootType
;
123 BDS_LOAD_OPTION
*BdsLoadOption
;
124 EFI_DEVICE_PATH
*DevicePath
;
125 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
126 EFI_DEVICE_PATH_PROTOCOL
*InitrdPathNode
;
129 SupportedBootDevice
= NULL
;
131 // List the Boot Devices supported
132 Status
= SelectBootDevice(&SupportedBootDevice
);
133 if (EFI_ERROR(Status
)) {
134 Status
= EFI_ABORTED
;
138 // Create the specific device path node
139 Print(L
"File path of the EFI Application or the kernel: ");
140 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (SupportedBootDevice
, &DevicePathNode
, &BootType
, &Attributes
);
141 if (EFI_ERROR(Status
)) {
142 Status
= EFI_ABORTED
;
145 // Append the Device Path node to the select device path
146 DevicePath
= AppendDevicePathNode (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)DevicePathNode
);
148 if (BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) {
149 // Create the specific device path node
150 Print(L
"File path of the initrd: ");
151 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (SupportedBootDevice
, &InitrdPathNode
, NULL
, NULL
);
152 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
153 Status
= EFI_ABORTED
;
157 if (InitrdPathNode
!= NULL
) {
158 // Append the Device Path node to the select device path
159 BootArguments
.LinuxAtagArguments
.InitrdPathList
= AppendDevicePathNode (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)InitrdPathNode
);
161 BootArguments
.LinuxAtagArguments
.InitrdPathList
= NULL
;
164 Print(L
"Arguments to pass to the binary: ");
165 Status
= GetHIInputAscii (BootArguments
.LinuxAtagArguments
.CmdLine
,BOOT_DEVICE_OPTION_MAX
);
166 if (EFI_ERROR(Status
)) {
167 Status
= EFI_ABORTED
;
168 goto FREE_DEVICE_PATH
;
170 BootArguments
.LinuxAtagArguments
.CmdLine
[BOOT_DEVICE_OPTION_MAX
]= '\0';
173 Print(L
"Description for this new Entry: ");
174 Status
= GetHIInputAscii (AsciiBootDescription
,BOOT_DEVICE_DESCRIPTION_MAX
);
175 if (EFI_ERROR(Status
)) {
176 Status
= EFI_ABORTED
;
177 goto FREE_DEVICE_PATH
;
180 // Convert Ascii into Unicode
181 BootDescription
= (CHAR16
*)AllocatePool(AsciiStrSize(AsciiBootDescription
) * sizeof(CHAR16
));
182 AsciiStrToUnicodeStr (AsciiBootDescription
, BootDescription
);
185 Status
= BootOptionCreate (Attributes
, BootDescription
, DevicePath
, BootType
, &BootArguments
, &BdsLoadOption
);
186 if (!EFI_ERROR(Status
)) {
187 InsertTailList (BootOptionsList
,&BdsLoadOption
->Link
);
190 FreePool (BootDescription
);
193 FreePool (DevicePath
);
197 if (Status
== EFI_ABORTED
) {
200 FreePool(SupportedBootDevice
);
206 BootMenuSelectBootOption (
207 IN LIST_ENTRY
*BootOptionsList
,
208 IN CONST CHAR16
* InputStatement
,
209 OUT BDS_LOAD_OPTION
**BdsLoadOption
214 BDS_LOAD_OPTION
*BootOption
;
215 UINTN BootOptionSelected
;
216 UINTN BootOptionCount
;
219 // Display the list of supported boot devices
221 for (Entry
= GetFirstNode (BootOptionsList
);
222 !IsNull (BootOptionsList
,Entry
);
223 Entry
= GetNextNode (BootOptionsList
,Entry
)
226 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
227 Print(L
"[%d] %s\n",BootOptionCount
,BootOption
->Description
);
230 CHAR16
* DevicePathTxt
;
231 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
233 Status
= gBS
->LocateProtocol(&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
234 ASSERT_EFI_ERROR(Status
);
235 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText(BootOption
->FilePathList
,TRUE
,TRUE
);
237 Print(L
"\t- %s\n",DevicePathTxt
);
238 if ((BDS_LOADER_TYPE
)ReadUnaligned32(&BootOption
->OptionalData
->LoaderType
) == BDS_LOADER_KERNEL_LINUX_ATAG
) {
239 Print(L
"\t- Arguments: %a\n",BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.CmdLine
);
242 FreePool(DevicePathTxt
);
248 // Get the index of the boot device to delete
249 BootOptionSelected
= 0;
250 while (BootOptionSelected
== 0) {
251 Print(InputStatement
);
252 Status
= GetHIInputInteger (&BootOptionSelected
);
253 if (EFI_ERROR(Status
)) {
255 } else if ((BootOptionSelected
== 0) || (BootOptionSelected
>= BootOptionCount
)) {
256 Print(L
"Invalid input (max %d)\n",BootOptionCount
-1);
257 BootOptionSelected
= 0;
261 // Get the structure of the Boot device to delete
263 for (Entry
= GetFirstNode (BootOptionsList
);
264 !IsNull (BootOptionsList
,Entry
);
265 Entry
= GetNextNode (BootOptionsList
,Entry
)
268 if (Index
== BootOptionSelected
) {
269 *BdsLoadOption
= LOAD_OPTION_FROM_LINK(Entry
);
279 BootMenuRemoveBootOption (
280 IN LIST_ENTRY
*BootOptionsList
284 BDS_LOAD_OPTION
*BootOption
;
286 Status
= BootMenuSelectBootOption (BootOptionsList
,L
"Delete entry: ",&BootOption
);
287 if (EFI_ERROR(Status
)) {
291 // Delete the BDS Load option structures
292 BootOptionDelete (BootOption
);
298 BootMenuUpdateBootOption (
299 IN LIST_ENTRY
*BootOptionsList
303 BDS_LOAD_OPTION
*BootOption
;
304 BDS_LOAD_OPTION_SUPPORT
*DeviceSupport
;
305 BDS_LOADER_ARGUMENTS BootArguments
;
306 CHAR8 AsciiBootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
307 CHAR16
*BootDescription
;
308 EFI_DEVICE_PATH
* DevicePath
;
309 BDS_LOADER_TYPE BootType
;
311 Status
= BootMenuSelectBootOption (BootOptionsList
,L
"Update entry: ",&BootOption
);
312 if (EFI_ERROR(Status
)) {
316 // Get the device support for this Boot Option
317 Status
= BootDeviceGetDeviceSupport (BootOption
,&DeviceSupport
);
318 if (EFI_ERROR(Status
)) {
319 Print(L
"Impossible to retrieve the supported device for the update\n");
320 return EFI_UNSUPPORTED
;
323 Print(L
"File path of the EFI Application or the kernel: ");
324 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
->FilePathList
, &DevicePath
, NULL
, NULL
);
325 if (EFI_ERROR(Status
)) {
326 Status
= EFI_ABORTED
;
330 BootType
= (BDS_LOADER_TYPE
)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->LoaderType
));
332 // TODO: Allow adding an initrd to a boot entry without one
333 if (BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) {
334 if (ReadUnaligned16(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathListLength
) > 0
335 && (EFI_DEVICE_PATH_PROTOCOL
*)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
)) != NULL
) {
337 Print(L
"File path of the initrd: ");
338 Status
= DeviceSupport
->UpdateDevicePathNode (
339 (EFI_DEVICE_PATH_PROTOCOL
*)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
)),
340 &BootArguments
.LinuxAtagArguments
.InitrdPathList
,
343 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
344 Status
= EFI_ABORTED
;
348 BootArguments
.LinuxAtagArguments
.InitrdPathList
= NULL
;
349 BootArguments
.LinuxAtagArguments
.InitrdPathListLength
= 0;
352 Print(L
"Arguments to pass to the binary: ");
353 if (ReadUnaligned32((CONST UINT32
*)&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.CmdLine
)) {
354 AsciiStrnCpy(BootArguments
.LinuxAtagArguments
.CmdLine
,
355 BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.CmdLine
,
356 BOOT_DEVICE_OPTION_MAX
+1);
358 BootArguments
.LinuxAtagArguments
.CmdLine
[0] = '\0';
360 Status
= EditHIInputAscii (BootArguments
.LinuxAtagArguments
.CmdLine
, BOOT_DEVICE_OPTION_MAX
);
361 if (EFI_ERROR(Status
)) {
362 Status
= EFI_ABORTED
;
363 goto FREE_DEVICE_PATH
;
367 Print(L
"Description for this new Entry: ");
368 UnicodeStrToAsciiStr (BootOption
->Description
, AsciiBootDescription
);
369 Status
= EditHIInputAscii (AsciiBootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
370 if (EFI_ERROR(Status
)) {
371 Status
= EFI_ABORTED
;
372 goto FREE_DEVICE_PATH
;
375 // Convert Ascii into Unicode
376 BootDescription
= (CHAR16
*)AllocatePool(AsciiStrSize(AsciiBootDescription
) * sizeof(CHAR16
));
377 AsciiStrToUnicodeStr (AsciiBootDescription
, BootDescription
);
380 Status
= BootOptionUpdate (BootOption
, BootOption
->Attributes
, BootDescription
, DevicePath
, BootType
, &BootArguments
);
382 FreePool (BootDescription
);
385 FreePool (DevicePath
);
388 if (Status
== EFI_ABORTED
) {
394 struct BOOT_MANAGER_ENTRY
{
395 CONST CHAR16
* Description
;
396 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
397 } BootManagerEntries
[] = {
398 { L
"Add Boot Device Entry", BootMenuAddBootOption
},
399 { L
"Update Boot Device Entry", BootMenuUpdateBootOption
},
400 { L
"Remove Boot Device Entry", BootMenuRemoveBootOption
},
405 IN LIST_ENTRY
*BootOptionsList
409 UINTN OptionSelected
;
410 UINTN BootManagerEntryCount
;
413 BootManagerEntryCount
= sizeof(BootManagerEntries
) / sizeof(struct BOOT_MANAGER_ENTRY
);
416 // Display Boot Manager menu
417 for (Index
= 0; Index
< BootManagerEntryCount
; Index
++) {
418 Print(L
"[%d] %s\n",Index
+1,BootManagerEntries
[Index
]);
420 Print(L
"[%d] Return to main menu\n",Index
+1);
422 // Select which entry to call
424 Status
= GetHIInputInteger (&OptionSelected
);
425 if (EFI_ERROR(Status
) || (OptionSelected
== (BootManagerEntryCount
+1))) {
426 if (EFI_ERROR(Status
)) {
430 } else if ((OptionSelected
> 0) && (OptionSelected
<= BootManagerEntryCount
)) {
431 Status
= BootManagerEntries
[OptionSelected
-1].Callback (BootOptionsList
);
440 IN LIST_ENTRY
*BootOptionsList
446 Status
= BdsLoadApplication(mImageHandle
, L
"Ebl");
447 if (Status
== EFI_NOT_FOUND
) {
448 Print (L
"Error: EFI Application not found.\n");
449 } else if (EFI_ERROR(Status
)) {
450 Print (L
"Error: Status Code: 0x%X\n",(UINT32
)Status
);
456 struct BOOT_MAIN_ENTRY
{
457 CONST CHAR16
* Description
;
458 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
459 } BootMainEntries
[] = {
461 { L
"Boot Manager", BootMenuManager
},
470 LIST_ENTRY BootOptionsList
;
472 UINTN BootOptionCount
;
475 BDS_LOAD_OPTION
*BootOption
;
476 UINTN BootOptionSelected
;
478 UINTN BootMainEntryCount
;
481 BootMainEntryCount
= sizeof(BootMainEntries
) / sizeof(struct BOOT_MAIN_ENTRY
);
484 BootOptionList (&BootOptionsList
);
489 // Display the Boot options
490 for (Entry
= GetFirstNode (&BootOptionsList
);
491 !IsNull (&BootOptionsList
,Entry
);
492 Entry
= GetNextNode (&BootOptionsList
,Entry
)
495 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
497 Print(L
"[%d] %s\n",OptionCount
,BootOption
->Description
);
500 CHAR16
* DevicePathTxt
;
501 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
503 Status
= gBS
->LocateProtocol(&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
504 if (EFI_ERROR(Status
)) {
505 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
506 DEBUG((EFI_D_ERROR
,"Error: Bds requires DevicePathToTextProtocol\n"));
509 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText(BootOption
->FilePathList
,TRUE
,TRUE
);
511 Print(L
"\t- %s\n",DevicePathTxt
);
512 if (ReadUnaligned32(&BootOption
->OptionalData
->LoaderType
) == BDS_LOADER_KERNEL_LINUX_ATAG
) {
513 if (ReadUnaligned16(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathListLength
) > 0
514 && (EFI_DEVICE_PATH_PROTOCOL
*)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
)) != NULL
) {
515 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL
*)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
)),TRUE
,TRUE
);
516 Print(L
"\t- Initrd: %s\n", DevicePathTxt
);
519 Print(L
"\t- Arguments: %a\n", BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.CmdLine
);
522 Print(L
"\t- LoaderType: %d\n", ReadUnaligned32 (&BootOption
->OptionalData
->LoaderType
));
524 FreePool(DevicePathTxt
);
529 BootOptionCount
= OptionCount
-1;
531 // Display the hardcoded Boot entries
532 for (Index
= 0; Index
< BootMainEntryCount
; Index
++) {
533 Print(L
"[%d] %s\n",OptionCount
,BootMainEntries
[Index
]);
537 // Request the boot entry from the user
538 BootOptionSelected
= 0;
539 while (BootOptionSelected
== 0) {
541 Status
= GetHIInputInteger (&BootOptionSelected
);
542 if (EFI_ERROR(Status
) || (BootOptionSelected
== 0) || (BootOptionSelected
> OptionCount
)) {
543 Print(L
"Invalid input (max %d)\n",(OptionCount
-1));
544 BootOptionSelected
= 0;
548 // Start the selected entry
549 if (BootOptionSelected
> BootOptionCount
) {
550 // Start the hardcoded entry
551 Status
= BootMainEntries
[BootOptionSelected
- BootOptionCount
- 1].Callback (&BootOptionsList
);
553 // Find the selected entry from the Boot#### list
555 for (Entry
= GetFirstNode (&BootOptionsList
);
556 !IsNull (&BootOptionsList
,Entry
);
557 Entry
= GetNextNode (&BootOptionsList
,Entry
)
560 if (Index
== BootOptionSelected
) {
561 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
567 Status
= BootOptionStart (BootOption
);