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
;
21 BootMenuAddBootOption (
22 IN LIST_ENTRY
*BootOptionsList
26 LIST_ENTRY SupportedDeviceList
;
27 UINTN SupportedDeviceCount
;
28 BDS_SUPPORTED_DEVICE
* SupportedBootDevice
;
30 UINTN SupportedDeviceSelected
;
31 CHAR8 AsciiBootOption
[BOOT_DEVICE_OPTION_MAX
];
32 CHAR8 AsciiBootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
33 CHAR16
*BootDescription
;
35 BDS_LOADER_TYPE BootType
;
37 BDS_LOAD_OPTION
*BdsLoadOption
;
38 EFI_DEVICE_PATH
* DevicePath
;
39 EFI_DEVICE_PATH_PROTOCOL
*DevicePathNode
;
42 SupportedBootDevice
= NULL
;
45 // List the Boot Devices supported
48 // Start all the drivers first
49 BdsConnectAllDrivers ();
51 // List the supported devices
52 Status
= BootDeviceListSupportedInit (&SupportedDeviceList
);
53 ASSERT_EFI_ERROR(Status
);
55 SupportedDeviceCount
= 0;
56 for (Entry
= GetFirstNode (&SupportedDeviceList
);
57 !IsNull (&SupportedDeviceList
,Entry
);
58 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
61 SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
62 Print(L
"[%d] %s\n",SupportedDeviceCount
+1,SupportedBootDevice
->Description
);
65 CHAR16
* DevicePathTxt
;
66 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
68 Status
= gBS
->LocateProtocol(&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
69 ASSERT_EFI_ERROR(Status
);
70 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText(SupportedBootDevice
->DevicePathProtocol
,TRUE
,TRUE
);
72 Print(L
"\t- %s\n",DevicePathTxt
);
74 FreePool(DevicePathTxt
);
77 SupportedDeviceCount
++;
80 if (SupportedDeviceCount
== 0) {
81 Print(L
"There is no supported device.\n");
87 // Select the Boot Device
89 SupportedDeviceSelected
= 0;
90 while (SupportedDeviceSelected
== 0) {
91 Print(L
"Select the Boot Device: ");
92 Status
= GetHIInputInteger (&SupportedDeviceSelected
);
93 if (EFI_ERROR(Status
)) {
96 } else if ((SupportedDeviceSelected
== 0) || (SupportedDeviceSelected
> SupportedDeviceCount
)) {
97 Print(L
"Invalid input (max %d)\n",SupportedDeviceSelected
);
98 SupportedDeviceSelected
= 0;
103 // Get the Device Path for the selected boot device
106 for (Entry
= GetFirstNode (&SupportedDeviceList
);
107 !IsNull (&SupportedDeviceList
,Entry
);
108 Entry
= GetNextNode (&SupportedDeviceList
,Entry
)
111 if (Index
== SupportedDeviceSelected
) {
112 SupportedBootDevice
= SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry
);
118 // Create the specific device path node
119 Status
= SupportedBootDevice
->Support
->CreateDevicePathNode (SupportedBootDevice
, &DevicePathNode
, &BootType
, &Attributes
);
120 if (EFI_ERROR(Status
)) {
121 Status
= EFI_ABORTED
;
124 // Append the Device Path node to the select device path
125 DevicePath
= AppendDevicePathNode (SupportedBootDevice
->DevicePathProtocol
, (CONST EFI_DEVICE_PATH_PROTOCOL
*)DevicePathNode
);
127 Print(L
"Arguments to pass to the binary: ");
128 Status
= GetHIInputAscii (AsciiBootOption
,BOOT_DEVICE_OPTION_MAX
);
129 if (EFI_ERROR(Status
)) {
130 Status
= EFI_ABORTED
;
131 goto FREE_DEVICE_PATH
;
134 Print(L
"Description for this new Entry: ");
135 Status
= GetHIInputAscii (AsciiBootDescription
,BOOT_DEVICE_DESCRIPTION_MAX
);
136 if (EFI_ERROR(Status
)) {
137 Status
= EFI_ABORTED
;
138 goto FREE_DEVICE_PATH
;
141 // Convert Ascii into Unicode
142 BootDescription
= (CHAR16
*)AllocatePool(AsciiStrSize(AsciiBootDescription
) * sizeof(CHAR16
));
143 AsciiStrToUnicodeStr (AsciiBootDescription
, BootDescription
);
146 Status
= BootOptionCreate (Attributes
, BootDescription
, DevicePath
, BootType
, AsciiBootOption
, &BdsLoadOption
);
147 if (!EFI_ERROR(Status
)) {
148 InsertTailList (BootOptionsList
,&BdsLoadOption
->Link
);
151 FreePool (BootDescription
);
154 FreePool (DevicePath
);
157 BootDeviceListSupportedFree (&SupportedDeviceList
);
163 BootMenuSelectBootOption (
164 IN LIST_ENTRY
*BootOptionsList
,
165 IN CONST CHAR16
* InputStatement
,
166 OUT BDS_LOAD_OPTION
**BdsLoadOption
171 BDS_LOAD_OPTION
*BootOption
;
172 UINTN BootOptionSelected
;
173 UINTN BootOptionCount
;
176 // Display the list of supported boot devices
178 for (Entry
= GetFirstNode (BootOptionsList
);
179 !IsNull (BootOptionsList
,Entry
);
180 Entry
= GetNextNode (BootOptionsList
,Entry
)
183 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
184 Print(L
"[%d] %s\n",BootOptionCount
,BootOption
->Description
);
187 CHAR16
* DevicePathTxt
;
188 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
190 Status
= gBS
->LocateProtocol(&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
191 ASSERT_EFI_ERROR(Status
);
192 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText(BootOption
->FilePathList
,TRUE
,TRUE
);
194 Print(L
"\t- %s\n",DevicePathTxt
);
195 if ((BootOption
->OptionalData
!= NULL
) && (BootOption
->OptionalData
->Arguments
!= NULL
)) {
196 Print(L
"\t- Arguments: %a\n",BootOption
->OptionalData
->Arguments
);
199 FreePool(DevicePathTxt
);
205 // Get the index of the boot device to delete
206 BootOptionSelected
= 0;
207 while (BootOptionSelected
== 0) {
208 Print(InputStatement
);
209 Status
= GetHIInputInteger (&BootOptionSelected
);
210 if (EFI_ERROR(Status
)) {
212 } else if ((BootOptionSelected
== 0) || (BootOptionSelected
>= BootOptionCount
)) {
213 Print(L
"Invalid input (max %d)\n",BootOptionCount
);
214 BootOptionSelected
= 0;
218 // Get the structure of the Boot device to delete
220 for (Entry
= GetFirstNode (BootOptionsList
);
221 !IsNull (BootOptionsList
,Entry
);
222 Entry
= GetNextNode (BootOptionsList
,Entry
)
225 if (Index
== BootOptionSelected
) {
226 *BdsLoadOption
= LOAD_OPTION_FROM_LINK(Entry
);
236 BootMenuRemoveBootOption (
237 IN LIST_ENTRY
*BootOptionsList
241 BDS_LOAD_OPTION
*BootOption
;
243 Status
= BootMenuSelectBootOption (BootOptionsList
,L
"Delete entry: ",&BootOption
);
244 if (EFI_ERROR(Status
)) {
248 // Delete the BDS Load option structures
249 BootOptionDelete (BootOption
);
255 BootMenuUpdateBootOption (
256 IN LIST_ENTRY
*BootOptionsList
260 BDS_LOAD_OPTION
*BootOption
;
261 BDS_LOAD_OPTION_SUPPORT
* DeviceSupport
;
262 CHAR8 AsciiBootOption
[BOOT_DEVICE_OPTION_MAX
];
263 CHAR8 AsciiBootDescription
[BOOT_DEVICE_DESCRIPTION_MAX
];
264 CHAR16
*BootDescription
;
265 EFI_DEVICE_PATH
* DevicePath
;
267 BDS_LOADER_TYPE BootType
;
269 Status
= BootMenuSelectBootOption (BootOptionsList
,L
"Update entry: ",&BootOption
);
270 if (EFI_ERROR(Status
)) {
274 // Get the device support for this Boot Option
275 Status
= BootDeviceGetDeviceSupport (BootOption
,&DeviceSupport
);
276 if (EFI_ERROR(Status
)) {
277 Print(L
"Impossible to retrieve the supported device for the update\n");
278 return EFI_UNSUPPORTED
;
281 Status
= DeviceSupport
->UpdateDevicePathNode (BootOption
,&DevicePath
,&BootType
,&Attributes
);
282 if (EFI_ERROR(Status
)) {
283 Status
= EFI_ABORTED
;
287 Print(L
"Arguments to pass to the binary: ");
288 if (BootOption
->OptionalData
) {
289 AsciiStrnCpy(AsciiBootOption
,BootOption
->OptionalData
->Arguments
,BOOT_DEVICE_FILEPATH_MAX
);
291 AsciiBootOption
[0] = '\0';
293 Status
= EditHIInputAscii (AsciiBootOption
,BOOT_DEVICE_OPTION_MAX
);
294 if (EFI_ERROR(Status
)) {
295 Status
= EFI_ABORTED
;
296 goto FREE_DEVICE_PATH
;
299 Print(L
"Description for this new Entry: ");
300 UnicodeStrToAsciiStr (BootOption
->Description
,AsciiBootDescription
);
301 Status
= EditHIInputAscii (AsciiBootDescription
,BOOT_DEVICE_DESCRIPTION_MAX
);
302 if (EFI_ERROR(Status
)) {
303 Status
= EFI_ABORTED
;
304 goto FREE_DEVICE_PATH
;
307 // Convert Ascii into Unicode
308 BootDescription
= (CHAR16
*)AllocatePool(AsciiStrSize(AsciiBootDescription
) * sizeof(CHAR16
));
309 AsciiStrToUnicodeStr (AsciiBootDescription
, BootDescription
);
312 Status
= BootOptionUpdate (BootOption
, Attributes
, BootDescription
, DevicePath
, BootType
, AsciiBootOption
);
314 FreePool (BootDescription
);
317 FreePool (DevicePath
);
323 struct BOOT_MANAGER_ENTRY
{
324 CONST CHAR16
* Description
;
325 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
326 } BootManagerEntries
[] = {
327 { L
"Add Boot Device Entry", BootMenuAddBootOption
},
328 { L
"Update Boot Device Entry", BootMenuUpdateBootOption
},
329 { L
"Remove Boot Device Entry", BootMenuRemoveBootOption
},
334 IN LIST_ENTRY
*BootOptionsList
338 UINTN OptionSelected
;
339 UINTN BootManagerEntryCount
;
342 BootManagerEntryCount
= sizeof(BootManagerEntries
) / sizeof(struct BOOT_MANAGER_ENTRY
);
345 // Display Boot Manager menu
346 for (Index
= 0; Index
< BootManagerEntryCount
; Index
++) {
347 Print(L
"[%d] %s\n",Index
+1,BootManagerEntries
[Index
]);
349 Print(L
"[%d] Return to main menu\n",Index
+1);
351 // Select which entry to call
353 Status
= GetHIInputInteger (&OptionSelected
);
354 if (EFI_ERROR(Status
) || (OptionSelected
== (BootManagerEntryCount
+1))) {
356 } else if ((OptionSelected
> 0) && (OptionSelected
<= BootManagerEntryCount
)) {
357 Status
= BootManagerEntries
[OptionSelected
-1].Callback (BootOptionsList
);
366 IN LIST_ENTRY
*BootOptionsList
372 Status
= BdsLoadApplication(mImageHandle
, L
"Ebl");
373 if (Status
== EFI_NOT_FOUND
) {
374 Print (L
"Error: EFI Application not found.\n");
375 } else if (EFI_ERROR(Status
)) {
376 Print (L
"Error: Status Code: 0x%X\n",(UINT32
)Status
);
382 struct BOOT_MAIN_ENTRY
{
383 CONST CHAR16
* Description
;
384 EFI_STATUS (*Callback
) (IN LIST_ENTRY
*BootOptionsList
);
385 } BootMainEntries
[] = {
387 { L
"Boot Manager", BootMenuManager
},
396 LIST_ENTRY BootOptionsList
;
398 UINTN BootOptionCount
;
401 BDS_LOAD_OPTION
*BootOption
;
402 UINTN BootOptionSelected
;
404 UINTN BootMainEntryCount
;
407 BootMainEntryCount
= sizeof(BootMainEntries
) / sizeof(struct BOOT_MAIN_ENTRY
);
410 BootOptionList (&BootOptionsList
);
415 // Display the Boot options
416 for (Entry
= GetFirstNode (&BootOptionsList
);
417 !IsNull (&BootOptionsList
,Entry
);
418 Entry
= GetNextNode (&BootOptionsList
,Entry
)
421 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
423 Print(L
"[%d] %s\n",OptionCount
,BootOption
->Description
);
426 CHAR16
* DevicePathTxt
;
427 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL
* DevicePathToTextProtocol
;
429 Status
= gBS
->LocateProtocol(&gEfiDevicePathToTextProtocolGuid
, NULL
, (VOID
**)&DevicePathToTextProtocol
);
430 if (EFI_ERROR(Status
)) {
431 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
432 DEBUG((EFI_D_ERROR
,"Error: Bds requires DevicePathToTextProtocol\n"));
435 DevicePathTxt
= DevicePathToTextProtocol
->ConvertDevicePathToText(BootOption
->FilePathList
,TRUE
,TRUE
);
437 Print(L
"\t- %s\n",DevicePathTxt
);
438 if (BootOption
->OptionalData
!= NULL
) {
439 Print(L
"\t- LoaderType: %d\n", ReadUnaligned32 (&BootOption
->OptionalData
->LoaderType
));
440 if (BootOption
->OptionalData
->Arguments
!= NULL
) {
441 Print(L
"\t- Arguments: %a\n",BootOption
->OptionalData
->Arguments
);
445 FreePool(DevicePathTxt
);
450 BootOptionCount
= OptionCount
-1;
452 // Display the hardcoded Boot entries
453 for (Index
= 0; Index
< BootMainEntryCount
; Index
++) {
454 Print(L
"[%d] %s\n",OptionCount
,BootMainEntries
[Index
]);
458 // Request the boot entry from the user
459 BootOptionSelected
= 0;
460 while (BootOptionSelected
== 0) {
462 Status
= GetHIInputInteger (&BootOptionSelected
);
463 if (EFI_ERROR(Status
) || (BootOptionSelected
== 0) || (BootOptionSelected
> OptionCount
)) {
464 Print(L
"Invalid input (max %d)\n",(OptionCount
-1));
465 BootOptionSelected
= 0;
469 // Start the selected entry
470 if (BootOptionSelected
> BootOptionCount
) {
471 // Start the hardcoded entry
472 Status
= BootMainEntries
[BootOptionSelected
- BootOptionCount
- 1].Callback (&BootOptionsList
);
474 // Find the selected entry from the Boot#### list
476 for (Entry
= GetFirstNode (&BootOptionsList
);
477 !IsNull (&BootOptionsList
,Entry
);
478 Entry
= GetNextNode (&BootOptionsList
,Entry
)
481 if (Index
== BootOptionSelected
) {
482 BootOption
= LOAD_OPTION_FROM_LINK(Entry
);
488 Status
= BootOptionStart (BootOption
);