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 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
121 BDS_LOADER_TYPE BootType
;
122 BDS_LOAD_OPTION
*BdsLoadOption
;
123 EFI_DEVICE_PATH
*DevicePath
;
124 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
125 EFI_DEVICE_PATH_PROTOCOL
*InitrdPathNode
;
128 SupportedBootDevice
= NULL
;
130 // List the Boot Devices supported
131 Status
= SelectBootDevice(&SupportedBootDevice
);
132 if (EFI_ERROR(Status
)) {
133 Status
= EFI_ABORTED
;
137 // Create the specific device path node
138 Print(L
"File path of the EFI Application or the kernel: ");
139 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (SupportedBootDevice
, &DevicePathNode
, &BootType
, &Attributes
);
140 if (EFI_ERROR(Status
)) {
141 Status
= EFI_ABORTED
;
144 // Append the Device Path node to the select device path
145 DevicePath
= AppendDevicePathNode (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)DevicePathNode
);
147 if (BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) {
148 // Create the specific device path node
149 Print(L
"File path of the initrd: ");
150 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (SupportedBootDevice
, &InitrdPathNode
, NULL
, NULL
);
151 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
152 Status
= EFI_ABORTED
;
156 if (InitrdPathNode
!= NULL
) {
157 // Append the Device Path node to the select device path
158 BootArguments
.LinuxAtagArguments
.InitrdPathList
= AppendDevicePathNode (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)InitrdPathNode
);
160 BootArguments
.LinuxAtagArguments
.InitrdPathList
= NULL
;
163 Print(L
"Arguments to pass to the binary: ");
164 Status
= GetHIInputAscii (BootArguments
.LinuxAtagArguments
.CmdLine
,BOOT_DEVICE_OPTION_MAX
);
165 if (EFI_ERROR(Status
)) {
166 Status
= EFI_ABORTED
;
167 goto FREE_DEVICE_PATH
;
169 BootArguments
.LinuxAtagArguments
.CmdLine
[BOOT_DEVICE_OPTION_MAX
]= '\0';
172 Print(L
"Description for this new Entry: ");
173 Status
= GetHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
174 if (EFI_ERROR(Status
)) {
175 Status
= EFI_ABORTED
;
176 goto FREE_DEVICE_PATH
;
180 Status
= BootOptionCreate (Attributes
, BootDescription
, DevicePath
, BootType
, &BootArguments
, &BdsLoadOption
);
181 if (!EFI_ERROR(Status
)) {
182 InsertTailList (BootOptionsList
,&BdsLoadOption
->Link
);
186 FreePool (DevicePath
);
190 if (Status
== EFI_ABORTED
) {
193 FreePool(SupportedBootDevice
);
199 BootMenuSelectBootOption (
200 IN LIST_ENTRY
*BootOptionsList
,
201 IN CONST CHAR16
* InputStatement
,
202 OUT BDS_LOAD_OPTION
**BdsLoadOption
207 BDS_LOAD_OPTION
*BootOption
;
208 UINTN BootOptionSelected
;
209 UINTN BootOptionCount
;
212 // Display the list of supported boot devices
214 for (Entry
= GetFirstNode (BootOptionsList
);
215 !IsNull (BootOptionsList
,Entry
);
216 Entry
= GetNextNode (BootOptionsList
,Entry
)
219 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
220 Print(L
"[%d] %s\n",BootOptionCount
,BootOption
->Description
);
223 CHAR16
* DevicePathTxt
;
224 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
226 Status
= gBS
->LocateProtocol(&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
227 ASSERT_EFI_ERROR(Status
);
228 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText(BootOption
->FilePathList
,TRUE
,TRUE
);
230 Print(L
"\t- %s\n",DevicePathTxt
);
231 if ((BDS_LOADER_TYPE
)ReadUnaligned32(&BootOption
->OptionalData
->LoaderType
) == BDS_LOADER_KERNEL_LINUX_ATAG
) {
232 Print(L
"\t- Arguments: %a\n",BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.CmdLine
);
235 FreePool(DevicePathTxt
);
241 // Get the index of the boot device to delete
242 BootOptionSelected
= 0;
243 while (BootOptionSelected
== 0) {
244 Print(InputStatement
);
245 Status
= GetHIInputInteger (&BootOptionSelected
);
246 if (EFI_ERROR(Status
)) {
248 } else if ((BootOptionSelected
== 0) || (BootOptionSelected
>= BootOptionCount
)) {
249 Print(L
"Invalid input (max %d)\n",BootOptionCount
-1);
250 BootOptionSelected
= 0;
254 // Get the structure of the Boot device to delete
256 for (Entry
= GetFirstNode (BootOptionsList
);
257 !IsNull (BootOptionsList
,Entry
);
258 Entry
= GetNextNode (BootOptionsList
,Entry
)
261 if (Index
== BootOptionSelected
) {
262 *BdsLoadOption
= LOAD_OPTION_FROM_LINK(Entry
);
272 BootMenuRemoveBootOption (
273 IN LIST_ENTRY
*BootOptionsList
277 BDS_LOAD_OPTION
*BootOption
;
279 Status
= BootMenuSelectBootOption (BootOptionsList
,L
"Delete entry: ",&BootOption
);
280 if (EFI_ERROR(Status
)) {
284 // Delete the BDS Load option structures
285 BootOptionDelete (BootOption
);
291 BootMenuUpdateBootOption (
292 IN LIST_ENTRY
*BootOptionsList
296 BDS_LOAD_OPTION
*BootOption
;
297 BDS_LOAD_OPTION_SUPPORT
*DeviceSupport
;
298 BDS_LOADER_ARGUMENTS BootArguments
;
299 CHAR16 BootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
300 EFI_DEVICE_PATH
* DevicePath
;
301 BDS_LOADER_TYPE BootType
;
303 Status
= BootMenuSelectBootOption (BootOptionsList
,L
"Update entry: ",&BootOption
);
304 if (EFI_ERROR(Status
)) {
308 // Get the device support for this Boot Option
309 Status
= BootDeviceGetDeviceSupport (BootOption
,&DeviceSupport
);
310 if (EFI_ERROR(Status
)) {
311 Print(L
"Impossible to retrieve the supported device for the update\n");
312 return EFI_UNSUPPORTED
;
315 Print(L
"File path of the EFI Application or the kernel: ");
316 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
->FilePathList
, &DevicePath
, NULL
, NULL
);
317 if (EFI_ERROR(Status
)) {
318 Status
= EFI_ABORTED
;
322 BootType
= (BDS_LOADER_TYPE
)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->LoaderType
));
324 // TODO: Allow adding an initrd to a boot entry without one
325 if (BootType
== BDS_LOADER_KERNEL_LINUX_ATAG
) {
326 if (ReadUnaligned16(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathListLength
) > 0
327 && (EFI_DEVICE_PATH_PROTOCOL
*)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
)) != NULL
) {
329 Print(L
"File path of the initrd: ");
330 Status
= DeviceSupport
->UpdateDevicePathNode (
331 (EFI_DEVICE_PATH_PROTOCOL
*)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
)),
332 &BootArguments
.LinuxAtagArguments
.InitrdPathList
,
335 if (EFI_ERROR(Status
) && Status
!= EFI_NOT_FOUND
) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
336 Status
= EFI_ABORTED
;
340 BootArguments
.LinuxAtagArguments
.InitrdPathList
= NULL
;
341 BootArguments
.LinuxAtagArguments
.InitrdPathListLength
= 0;
344 Print(L
"Arguments to pass to the binary: ");
345 if (ReadUnaligned32((CONST UINT32
*)&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.CmdLine
)) {
346 AsciiStrnCpy(BootArguments
.LinuxAtagArguments
.CmdLine
,
347 BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.CmdLine
,
348 BOOT_DEVICE_OPTION_MAX
+1);
350 BootArguments
.LinuxAtagArguments
.CmdLine
[0] = '\0';
352 Status
= EditHIInputAscii (BootArguments
.LinuxAtagArguments
.CmdLine
, BOOT_DEVICE_OPTION_MAX
);
353 if (EFI_ERROR(Status
)) {
354 Status
= EFI_ABORTED
;
355 goto FREE_DEVICE_PATH
;
359 Print(L
"Description for this new Entry: ");
360 Status
= EditHIInputStr (BootDescription
, BOOT_DEVICE_DESCRIPTION_MAX
);
361 if (EFI_ERROR(Status
)) {
362 Status
= EFI_ABORTED
;
363 goto FREE_DEVICE_PATH
;
367 Status
= BootOptionUpdate (BootOption
, BootOption
->Attributes
, BootDescription
, DevicePath
, BootType
, &BootArguments
);
370 FreePool (DevicePath
);
373 if (Status
== EFI_ABORTED
) {
379 struct BOOT_MANAGER_ENTRY
{
380 CONST CHAR16
* Description
;
381 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
382 } BootManagerEntries
[] = {
383 { L
"Add Boot Device Entry", BootMenuAddBootOption
},
384 { L
"Update Boot Device Entry", BootMenuUpdateBootOption
},
385 { L
"Remove Boot Device Entry", BootMenuRemoveBootOption
},
390 IN LIST_ENTRY
*BootOptionsList
394 UINTN OptionSelected
;
395 UINTN BootManagerEntryCount
;
398 BootManagerEntryCount
= sizeof(BootManagerEntries
) / sizeof(struct BOOT_MANAGER_ENTRY
);
401 // Display Boot Manager menu
402 for (Index
= 0; Index
< BootManagerEntryCount
; Index
++) {
403 Print(L
"[%d] %s\n",Index
+1,BootManagerEntries
[Index
]);
405 Print(L
"[%d] Return to main menu\n",Index
+1);
407 // Select which entry to call
409 Status
= GetHIInputInteger (&OptionSelected
);
410 if (EFI_ERROR(Status
) || (OptionSelected
== (BootManagerEntryCount
+1))) {
411 if (EFI_ERROR(Status
)) {
415 } else if ((OptionSelected
> 0) && (OptionSelected
<= BootManagerEntryCount
)) {
416 Status
= BootManagerEntries
[OptionSelected
-1].Callback (BootOptionsList
);
425 IN LIST_ENTRY
*BootOptionsList
431 Status
= BdsLoadApplication(mImageHandle
, L
"Ebl");
432 if (Status
== EFI_NOT_FOUND
) {
433 Print (L
"Error: EFI Application not found.\n");
434 } else if (EFI_ERROR(Status
)) {
435 Print (L
"Error: Status Code: 0x%X\n",(UINT32
)Status
);
441 struct BOOT_MAIN_ENTRY
{
442 CONST CHAR16
* Description
;
443 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
444 } BootMainEntries
[] = {
446 { L
"Boot Manager", BootMenuManager
},
455 LIST_ENTRY BootOptionsList
;
457 UINTN BootOptionCount
;
460 BDS_LOAD_OPTION
*BootOption
;
461 UINTN BootOptionSelected
;
463 UINTN BootMainEntryCount
;
466 BootMainEntryCount
= sizeof(BootMainEntries
) / sizeof(struct BOOT_MAIN_ENTRY
);
469 BootOptionList (&BootOptionsList
);
474 // Display the Boot options
475 for (Entry
= GetFirstNode (&BootOptionsList
);
476 !IsNull (&BootOptionsList
,Entry
);
477 Entry
= GetNextNode (&BootOptionsList
,Entry
)
480 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
482 Print(L
"[%d] %s\n",OptionCount
,BootOption
->Description
);
485 CHAR16
* DevicePathTxt
;
486 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
488 Status
= gBS
->LocateProtocol(&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
489 if (EFI_ERROR(Status
)) {
490 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
491 DEBUG((EFI_D_ERROR
,"Error: Bds requires DevicePathToTextProtocol\n"));
494 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText(BootOption
->FilePathList
,TRUE
,TRUE
);
496 Print(L
"\t- %s\n",DevicePathTxt
);
497 if (ReadUnaligned32(&BootOption
->OptionalData
->LoaderType
) == BDS_LOADER_KERNEL_LINUX_ATAG
) {
498 if (ReadUnaligned16(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathListLength
) > 0
499 && (EFI_DEVICE_PATH_PROTOCOL
*)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
)) != NULL
) {
500 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText((EFI_DEVICE_PATH_PROTOCOL
*)ReadUnaligned32((UINT32
*)(&BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.InitrdPathList
)),TRUE
,TRUE
);
501 Print(L
"\t- Initrd: %s\n", DevicePathTxt
);
504 Print(L
"\t- Arguments: %a\n", BootOption
->OptionalData
->Arguments
.LinuxAtagArguments
.CmdLine
);
507 Print(L
"\t- LoaderType: %d\n", ReadUnaligned32 (&BootOption
->OptionalData
->LoaderType
));
509 FreePool(DevicePathTxt
);
514 BootOptionCount
= OptionCount
-1;
516 // Display the hardcoded Boot entries
517 for (Index
= 0; Index
< BootMainEntryCount
; Index
++) {
518 Print(L
"[%d] %s\n",OptionCount
,BootMainEntries
[Index
]);
522 // Request the boot entry from the user
523 BootOptionSelected
= 0;
524 while (BootOptionSelected
== 0) {
526 Status
= GetHIInputInteger (&BootOptionSelected
);
527 if (EFI_ERROR(Status
) || (BootOptionSelected
== 0) || (BootOptionSelected
> OptionCount
)) {
528 Print(L
"Invalid input (max %d)\n",(OptionCount
-1));
529 BootOptionSelected
= 0;
533 // Start the selected entry
534 if (BootOptionSelected
> BootOptionCount
) {
535 // Start the hardcoded entry
536 Status
= BootMainEntries
[BootOptionSelected
- BootOptionCount
- 1].Callback (&BootOptionsList
);
538 // Find the selected entry from the Boot#### list
540 for (Entry
= GetFirstNode (&BootOptionsList
);
541 !IsNull (&BootOptionsList
,Entry
);
542 Entry
= GetNextNode (&BootOptionsList
,Entry
)
545 if (Index
== BootOptionSelected
) {
546 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
552 Status
= BootOptionStart (BootOption
);