]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Bds/BootMenu.c
ArmPlatformPkg/Bds: Added support for booting legacy kernel from BDS
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootMenu.c
CommitLineData
ea46ebbe 1/** @file\r
2*\r
f2c730d3 3* Copyright (c) 2011 - 2015, ARM Limited. All rights reserved.\r
ea46ebbe 4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "BdsInternal.h"\r
16\r
aeaf64d6 17#include <Guid/ArmGlobalVariableHob.h>\r
18\r
0ae6a518 19#include <libfdt.h>\r
ea46ebbe 20\r
019680b3
RC
21/**\r
22 Worker function that displays the list of boot options that is passed in.\r
23\r
24 The function loops over the entries of the list of boot options that is passed\r
25 in. For each entry, the boot option description is displayed on a single line\r
26 along with the position of the option in the list. In debug mode, the UEFI\r
27 device path and the arguments of the boot option are displayed as well in\r
28 subsequent lines.\r
29\r
30 @param[in] BootOptionsList List of the boot options\r
31\r
32**/\r
33STATIC\r
34VOID\r
35DisplayBootOptions (\r
36 IN LIST_ENTRY* BootOptionsList\r
37 )\r
38{\r
39 EFI_STATUS Status;\r
40 UINTN BootOptionCount;\r
41 LIST_ENTRY *Entry;\r
42 BDS_LOAD_OPTION *BdsLoadOption;\r
43 BOOLEAN IsUnicode;\r
44\r
45 BootOptionCount = 0 ;\r
46 for (Entry = GetFirstNode (BootOptionsList);\r
47 !IsNull (BootOptionsList, Entry);\r
48 Entry = GetNextNode (BootOptionsList, Entry)\r
49 ) {\r
50\r
51 BdsLoadOption = LOAD_OPTION_FROM_LINK (Entry);\r
52 Print (L"[%d] %s\n", ++BootOptionCount, BdsLoadOption->Description);\r
53\r
54 DEBUG_CODE_BEGIN ();\r
55 CHAR16* DevicePathTxt;\r
56 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
019680b3
RC
57\r
58 Status = gBS->LocateProtocol (\r
59 &gEfiDevicePathToTextProtocolGuid,\r
60 NULL,\r
61 (VOID **)&DevicePathToTextProtocol\r
62 );\r
63 ASSERT_EFI_ERROR (Status);\r
64 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (\r
65 BdsLoadOption->FilePathList,\r
66 TRUE,\r
67 TRUE\r
68 );\r
69 Print (L"\t- %s\n", DevicePathTxt);\r
70\r
8b129b7b
OM
71 if (IsPrintableString (BdsLoadOption->OptionalData, &IsUnicode)) {\r
72 if (IsUnicode) {\r
73 Print (L"\t- Arguments: %s\n", BdsLoadOption->OptionalData);\r
74 } else {\r
75 AsciiPrint ("\t- Arguments: %a\n", BdsLoadOption->OptionalData);\r
019680b3
RC
76 }\r
77 }\r
78\r
79 FreePool (DevicePathTxt);\r
80 DEBUG_CODE_END ();\r
81 }\r
82}\r
83\r
84/**\r
85 Worker function that asks for a boot option to be selected and returns a\r
86 pointer to the structure describing the selected boot option.\r
87\r
88 @param[in] BootOptionsList List of the boot options\r
89\r
90 @retval EFI_SUCCESS Selection succeeded\r
91 @retval !EFI_SUCCESS Input error or input cancelled\r
92\r
93**/\r
94STATIC\r
95EFI_STATUS\r
96SelectBootOption (\r
97 IN LIST_ENTRY* BootOptionsList,\r
98 IN CONST CHAR16* InputStatement,\r
99 OUT BDS_LOAD_OPTION_ENTRY** BdsLoadOptionEntry\r
100 )\r
101{\r
102 EFI_STATUS Status;\r
103 UINTN BootOptionCount;\r
104 UINT16 *BootOrder;\r
105 LIST_ENTRY* Entry;\r
106 UINTN BootOptionSelected;\r
107 UINTN Index;\r
108\r
109 // Get the number of boot options\r
110 Status = GetGlobalEnvironmentVariable (\r
111 L"BootOrder", NULL, &BootOptionCount, (VOID**)&BootOrder\r
112 );\r
113 if (EFI_ERROR (Status)) {\r
114 goto ErrorExit;\r
115 }\r
116 FreePool (BootOrder);\r
117 BootOptionCount /= sizeof (UINT16);\r
118\r
119 // Check if a valid boot option(s) is found\r
120 if (BootOptionCount == 0) {\r
121 if (StrCmp (InputStatement, DELETE_BOOT_ENTRY) == 0) {\r
122 Print (L"Nothing to remove!\n");\r
123 } else if (StrCmp (InputStatement, UPDATE_BOOT_ENTRY) == 0) {\r
124 Print (L"Nothing to update!\n");\r
125 } else if (StrCmp (InputStatement, MOVE_BOOT_ENTRY) == 0) {\r
126 Print (L"Nothing to move!\n");\r
127 } else {\r
128 Print (L"No supported Boot Entry.\n");\r
129 }\r
130 return EFI_NOT_FOUND;\r
131 }\r
132\r
133 // Get the index of the boot device to delete\r
134 BootOptionSelected = 0;\r
135 while (BootOptionSelected == 0) {\r
136 Print (InputStatement);\r
137 Status = GetHIInputInteger (&BootOptionSelected);\r
138 if (EFI_ERROR (Status)) {\r
139 Print (L"\n");\r
140 goto ErrorExit;\r
141 } else if ((BootOptionSelected == 0) || (BootOptionSelected > BootOptionCount)) {\r
142 Print (L"Invalid input (max %d)\n", BootOptionCount);\r
143 BootOptionSelected = 0;\r
144 }\r
145 }\r
146\r
147 // Get the structure of the Boot device to delete\r
148 Index = 1;\r
149 for (Entry = GetFirstNode (BootOptionsList);\r
150 !IsNull (BootOptionsList, Entry);\r
151 Entry = GetNextNode (BootOptionsList,Entry)\r
152 )\r
153 {\r
154 if (Index == BootOptionSelected) {\r
155 *BdsLoadOptionEntry = LOAD_OPTION_ENTRY_FROM_LINK (Entry);\r
156 break;\r
157 }\r
158 Index++;\r
159 }\r
aeaf64d6 160\r
019680b3
RC
161ErrorExit:\r
162 return Status;\r
163}\r
164\r
165STATIC\r
ea46ebbe 166EFI_STATUS\r
656416bc 167SelectBootDevice (\r
168 OUT BDS_SUPPORTED_DEVICE** SupportedBootDevice\r
ea46ebbe 169 )\r
170{\r
656416bc 171 EFI_STATUS Status;\r
ea46ebbe 172 LIST_ENTRY SupportedDeviceList;\r
173 UINTN SupportedDeviceCount;\r
ea46ebbe 174 LIST_ENTRY* Entry;\r
175 UINTN SupportedDeviceSelected;\r
ea46ebbe 176 UINTN Index;\r
ea46ebbe 177\r
178 //\r
179 // List the Boot Devices supported\r
180 //\r
181\r
182 // Start all the drivers first\r
183 BdsConnectAllDrivers ();\r
184\r
185 // List the supported devices\r
186 Status = BootDeviceListSupportedInit (&SupportedDeviceList);\r
187 ASSERT_EFI_ERROR(Status);\r
188\r
189 SupportedDeviceCount = 0;\r
190 for (Entry = GetFirstNode (&SupportedDeviceList);\r
191 !IsNull (&SupportedDeviceList,Entry);\r
192 Entry = GetNextNode (&SupportedDeviceList,Entry)\r
193 )\r
194 {\r
656416bc 195 *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
196 Print(L"[%d] %s\n",SupportedDeviceCount+1,(*SupportedBootDevice)->Description);\r
ea46ebbe 197\r
198 DEBUG_CODE_BEGIN();\r
199 CHAR16* DevicePathTxt;\r
200 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
201\r
ff7666c5 202 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
ea46ebbe 203 ASSERT_EFI_ERROR(Status);\r
ff7666c5 204 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ((*SupportedBootDevice)->DevicePathProtocol,TRUE,TRUE);\r
ea46ebbe 205\r
206 Print(L"\t- %s\n",DevicePathTxt);\r
207\r
208 FreePool(DevicePathTxt);\r
209 DEBUG_CODE_END();\r
210\r
211 SupportedDeviceCount++;\r
212 }\r
213\r
214 if (SupportedDeviceCount == 0) {\r
215 Print(L"There is no supported device.\n");\r
216 Status = EFI_ABORTED;\r
217 goto EXIT;\r
218 }\r
219\r
220 //\r
221 // Select the Boot Device\r
222 //\r
223 SupportedDeviceSelected = 0;\r
224 while (SupportedDeviceSelected == 0) {\r
225 Print(L"Select the Boot Device: ");\r
226 Status = GetHIInputInteger (&SupportedDeviceSelected);\r
227 if (EFI_ERROR(Status)) {\r
228 Status = EFI_ABORTED;\r
229 goto EXIT;\r
230 } else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) {\r
ff7666c5 231 Print(L"Invalid input (max %d)\n",SupportedDeviceCount);\r
ea46ebbe 232 SupportedDeviceSelected = 0;\r
233 }\r
234 }\r
235\r
236 //\r
237 // Get the Device Path for the selected boot device\r
238 //\r
239 Index = 1;\r
240 for (Entry = GetFirstNode (&SupportedDeviceList);\r
241 !IsNull (&SupportedDeviceList,Entry);\r
242 Entry = GetNextNode (&SupportedDeviceList,Entry)\r
243 )\r
244 {\r
245 if (Index == SupportedDeviceSelected) {\r
656416bc 246 *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
ea46ebbe 247 break;\r
248 }\r
249 Index++;\r
250 }\r
aeaf64d6 251\r
656416bc 252EXIT:\r
253 BootDeviceListSupportedFree (&SupportedDeviceList, *SupportedBootDevice);\r
254 return Status;\r
255}\r
256\r
257EFI_STATUS\r
258BootMenuAddBootOption (\r
259 IN LIST_ENTRY *BootOptionsList\r
260 )\r
261{\r
2ccfb71e 262 EFI_STATUS Status;\r
263 BDS_SUPPORTED_DEVICE* SupportedBootDevice;\r
74b96132 264 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
06044819 265 CHAR16 CmdLine[BOOT_DEVICE_OPTION_MAX];\r
2ccfb71e 266 UINT32 Attributes;\r
a6e97d28 267 BDS_LOAD_OPTION_ENTRY *BdsLoadOptionEntry;\r
2ccfb71e 268 EFI_DEVICE_PATH *DevicePath;\r
ecc62d13 269 EFI_DEVICE_PATH_PROTOCOL *DevicePathNodes;\r
90a44ec4
OM
270 UINT8* OptionalData;\r
271 UINTN OptionalDataSize;\r
5d9e9d1a
OM
272 BOOLEAN EfiBinary;\r
273 CHAR16 *LinuxDevicePath;\r
656416bc 274\r
275 Attributes = 0;\r
276 SupportedBootDevice = NULL;\r
277\r
278 // List the Boot Devices supported\r
2ccfb71e 279 Status = SelectBootDevice (&SupportedBootDevice);\r
656416bc 280 if (EFI_ERROR(Status)) {\r
281 Status = EFI_ABORTED;\r
282 goto EXIT;\r
283 }\r
ea46ebbe 284\r
285 // Create the specific device path node\r
5d9e9d1a
OM
286 if (FeaturePcdGet (PcdBdsLinuxSupport) && mLinuxLoaderDevicePath) {\r
287 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application or the kernel", &DevicePathNodes);\r
288 } else {\r
289 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application", &DevicePathNodes);\r
290 }\r
291 if (EFI_ERROR (Status)) {\r
ea46ebbe 292 Status = EFI_ABORTED;\r
293 goto EXIT;\r
294 }\r
ecc62d13 295 // Append the Device Path to the selected device path\r
296 DevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNodes);\r
297 if (DevicePath == NULL) {\r
298 Status = EFI_OUT_OF_RESOURCES;\r
299 goto EXIT;\r
300 }\r
ea46ebbe 301\r
5d9e9d1a
OM
302 // Is it an EFI application?\r
303 if (FeaturePcdGet (PcdBdsLinuxSupport) && mLinuxLoaderDevicePath) {\r
304 Status = IsEfiBinary (DevicePath, &EfiBinary);\r
305 if (EFI_ERROR (Status)) {\r
306 Status = EFI_ABORTED;\r
307 goto EXIT;\r
308 }\r
309\r
310 if (EfiBinary == FALSE) {\r
311 Print (L"It is assumed the binary is a Linux kernel and the embedded Linux Loader is going to be used.\n");\r
312 Print (L"Supported command line formats by the embedded Linux Loader:\n");\r
313 Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\"\n");\r
314 Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -f <EFI Device Path of the Linux initrd>\n");\r
315 Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -a <Machine Type for ATAG Linux kernel>\n");\r
316\r
317 // Copy the Linux path into the command line\r
318 LinuxDevicePath = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
319 CopyMem (CmdLine, LinuxDevicePath, MAX (sizeof (CmdLine), StrSize (LinuxDevicePath)));\r
320 FreePool (LinuxDevicePath);\r
321\r
322 // Free the generated Device Path\r
323 FreePool (DevicePath);\r
324 // and use the embedded Linux Loader as the EFI application\r
325 DevicePath = mLinuxLoaderDevicePath;\r
326 } else {\r
327 CmdLine[0] = L'\0';\r
328 }\r
329 } else {\r
330 CmdLine[0] = L'\0';\r
331 }\r
332\r
8b129b7b 333 Print (L"Arguments to pass to the EFI Application: ");\r
5d9e9d1a 334 Status = EditHIInputStr (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
8b129b7b
OM
335 if (EFI_ERROR (Status)) {\r
336 Status = EFI_ABORTED;\r
337 goto EXIT;\r
55a9f75d
OM
338 }\r
339\r
8b129b7b
OM
340 OptionalData = (UINT8*)CmdLine;\r
341 OptionalDataSize = StrSize (CmdLine);\r
ea46ebbe 342\r
343 Print(L"Description for this new Entry: ");\r
74b96132 344 Status = GetHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
ea46ebbe 345 if (EFI_ERROR(Status)) {\r
346 Status = EFI_ABORTED;\r
347 goto FREE_DEVICE_PATH;\r
348 }\r
349\r
ea46ebbe 350 // Create new entry\r
a6e97d28 351 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY));\r
8b129b7b 352 Status = BootOptionCreate (Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize, &BdsLoadOptionEntry->BdsLoadOption);\r
ea46ebbe 353 if (!EFI_ERROR(Status)) {\r
a6e97d28 354 InsertTailList (BootOptionsList, &BdsLoadOptionEntry->Link);\r
ea46ebbe 355 }\r
356\r
ea46ebbe 357FREE_DEVICE_PATH:\r
358 FreePool (DevicePath);\r
359\r
360EXIT:\r
656416bc 361 if (Status == EFI_ABORTED) {\r
362 Print(L"\n");\r
363 }\r
364 FreePool(SupportedBootDevice);\r
ea46ebbe 365 return Status;\r
366}\r
367\r
ea46ebbe 368EFI_STATUS\r
369BootMenuRemoveBootOption (\r
370 IN LIST_ENTRY *BootOptionsList\r
371 )\r
372{\r
a6e97d28 373 EFI_STATUS Status;\r
374 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;\r
ea46ebbe 375\r
019680b3
RC
376 DisplayBootOptions (BootOptionsList);\r
377 Status = SelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, &BootOptionEntry);\r
378 if (EFI_ERROR (Status)) {\r
ea46ebbe 379 return Status;\r
380 }\r
381\r
a6e97d28 382 // If the Boot Option was attached to a list remove it\r
383 if (!IsListEmpty (&BootOptionEntry->Link)) {\r
384 // Remove the entry from the list\r
385 RemoveEntryList (&BootOptionEntry->Link);\r
386 }\r
387\r
ea46ebbe 388 // Delete the BDS Load option structures\r
a6e97d28 389 BootOptionDelete (BootOptionEntry->BdsLoadOption);\r
ea46ebbe 390\r
391 return EFI_SUCCESS;\r
392}\r
393\r
394EFI_STATUS\r
395BootMenuUpdateBootOption (\r
396 IN LIST_ENTRY *BootOptionsList\r
397 )\r
398{\r
2ccfb71e 399 EFI_STATUS Status;\r
a6e97d28 400 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;\r
2ccfb71e 401 BDS_LOAD_OPTION *BootOption;\r
402 BDS_LOAD_OPTION_SUPPORT* DeviceSupport;\r
74b96132 403 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
2ccfb71e 404 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];\r
3b3b72d6 405 CHAR16 UnicodeCmdLine[BOOT_DEVICE_OPTION_MAX];\r
5d9e9d1a 406 CHAR16 *LinuxDevicePath;\r
14238a61 407 EFI_DEVICE_PATH *DevicePath;\r
90a44ec4
OM
408 UINT8* OptionalData;\r
409 UINTN OptionalDataSize;\r
3b3b72d6
OM
410 BOOLEAN IsPrintable;\r
411 BOOLEAN IsUnicode;\r
5d9e9d1a 412 BOOLEAN EfiBinary;\r
ea46ebbe 413\r
019680b3
RC
414 DisplayBootOptions (BootOptionsList);\r
415 Status = SelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry);\r
416 if (EFI_ERROR (Status)) {\r
ea46ebbe 417 return Status;\r
418 }\r
a6e97d28 419 BootOption = BootOptionEntry->BdsLoadOption;\r
ea46ebbe 420\r
421 // Get the device support for this Boot Option\r
22a262c8 422 Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport);\r
ea46ebbe 423 if (EFI_ERROR(Status)) {\r
ff7666c5 424 Print(L"Not possible to retrieve the supported device for the update\n");\r
ea46ebbe 425 return EFI_UNSUPPORTED;\r
426 }\r
427\r
5d9e9d1a
OM
428 EfiBinary = TRUE;\r
429 if (FeaturePcdGet (PcdBdsLinuxSupport) && mLinuxLoaderDevicePath) {\r
430 Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath);\r
431 if (EFI_ERROR (Status)) {\r
432 Status = EFI_ABORTED;\r
433 goto EXIT;\r
434 }\r
435\r
436 // Is it an EFI application?\r
437 Status = IsEfiBinary (DevicePath, &EfiBinary);\r
438 if (EFI_ERROR (Status)) {\r
439 Status = EFI_ABORTED;\r
440 goto EXIT;\r
441 }\r
442\r
443 if (EfiBinary == FALSE) {\r
444 Print (L"It is assumed the binary is a Linux kernel and the embedded Linux Loader is going to be used.\n");\r
445 Print (L"Supported command line formats by the embedded Linux Loader:\n");\r
446 Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\"\n");\r
447 Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -f <EFI Device Path of the Linux initrd>\n");\r
448 Print (L"- <EFI device path of the Linux kernel> -c \"<Linux kernel command line>\" -a <Machine Type for ATAG Linux kernel>\n");\r
449\r
450 // Copy the Linux path into the command line\r
451 LinuxDevicePath = ConvertDevicePathToText (DevicePath, FALSE, FALSE);\r
452 CopyMem (UnicodeCmdLine, LinuxDevicePath, MAX (sizeof (UnicodeCmdLine), StrSize (LinuxDevicePath)));\r
453 FreePool (LinuxDevicePath);\r
454\r
455 // Free the generated Device Path\r
456 FreePool (DevicePath);\r
457 // and use the embedded Linux Loader as the EFI application\r
458 DevicePath = mLinuxLoaderDevicePath;\r
459\r
460 // The command line is a unicode printable string\r
461 IsPrintable = TRUE;\r
462 IsUnicode = TRUE;\r
463 }\r
464 } else {\r
465 Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application", &DevicePath);\r
466 if (EFI_ERROR (Status)) {\r
467 Status = EFI_ABORTED;\r
468 goto EXIT;\r
469 }\r
ea46ebbe 470 }\r
471\r
8b129b7b 472 Print (L"Arguments to pass to the EFI Application: ");\r
22a262c8 473\r
5d9e9d1a
OM
474 // When the command line has not been initialized by the embedded Linux loader earlier\r
475 if (EfiBinary) {\r
476 if (BootOption->OptionalDataSize > 0) {\r
477 IsPrintable = IsPrintableString (BootOption->OptionalData, &IsUnicode);\r
478 if (IsPrintable) {\r
479 //\r
480 // The size in bytes of the string, final zero included, should\r
481 // be equal to or at least lower than "BootOption->OptionalDataSize"\r
482 // and the "IsPrintableString()" has already tested that the length\r
483 // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,\r
484 // final '\0' included. We can thus copy the string for editing\r
485 // using "CopyMem()". Furthermore, note that in the case of an Unicode\r
486 // string "StrnCpy()" and "StrCpy()" can not be used to copy the\r
487 // string because the data pointed to by "BootOption->OptionalData"\r
488 // is not necessarily 2-byte aligned.\r
489 //\r
490 if (IsUnicode) {\r
491 CopyMem (\r
492 UnicodeCmdLine, BootOption->OptionalData,\r
493 MIN (sizeof (UnicodeCmdLine),\r
494 BootOption->OptionalDataSize)\r
495 );\r
496 } else {\r
497 CopyMem (\r
498 CmdLine, BootOption->OptionalData,\r
499 MIN (sizeof (CmdLine),\r
500 BootOption->OptionalDataSize)\r
501 );\r
502 }\r
3e710183 503 }\r
5d9e9d1a
OM
504 } else {\r
505 UnicodeCmdLine[0] = L'\0';\r
506 IsPrintable = TRUE;\r
507 IsUnicode = TRUE;\r
656416bc 508 }\r
8b129b7b 509 }\r
3b3b72d6 510\r
8b129b7b
OM
511 // We do not request arguments for OptionalData that cannot be printed\r
512 if (IsPrintable) {\r
513 if (IsUnicode) {\r
514 Status = EditHIInputStr (UnicodeCmdLine, BOOT_DEVICE_OPTION_MAX);\r
515 if (EFI_ERROR (Status)) {\r
516 Status = EFI_ABORTED;\r
517 goto FREE_DEVICE_PATH;\r
3b3b72d6 518 }\r
3b3b72d6 519\r
8b129b7b
OM
520 OptionalData = (UINT8*)UnicodeCmdLine;\r
521 OptionalDataSize = StrSize (UnicodeCmdLine);\r
3b3b72d6 522 } else {\r
8b129b7b
OM
523 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
524 if (EFI_ERROR (Status)) {\r
525 Status = EFI_ABORTED;\r
526 goto FREE_DEVICE_PATH;\r
527 }\r
528\r
529 OptionalData = (UINT8*)CmdLine;\r
530 OptionalDataSize = AsciiStrSize (CmdLine);\r
3b3b72d6 531 }\r
8b129b7b
OM
532 } else {\r
533 // We keep the former OptionalData\r
534 OptionalData = BootOption->OptionalData;\r
535 OptionalDataSize = BootOption->OptionalDataSize;\r
ea46ebbe 536 }\r
537\r
538 Print(L"Description for this new Entry: ");\r
3e710183 539 StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX);\r
74b96132 540 Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
ea46ebbe 541 if (EFI_ERROR(Status)) {\r
542 Status = EFI_ABORTED;\r
543 goto FREE_DEVICE_PATH;\r
544 }\r
545\r
ea46ebbe 546 // Update the entry\r
8b129b7b 547 Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize);\r
ea46ebbe 548\r
ea46ebbe 549FREE_DEVICE_PATH:\r
550 FreePool (DevicePath);\r
551\r
552EXIT:\r
326d1df9 553 if (Status == EFI_ABORTED) {\r
554 Print(L"\n");\r
555 }\r
ea46ebbe 556 return Status;\r
557}\r
558\r
019680b3
RC
559/**\r
560 Reorder boot options\r
561\r
562 Ask for the boot option to move and then move it when up or down arrows\r
563 are pressed. This function is called when the user selects the "Reorder Boot\r
564 Device Entries" entry in the boot manager menu.\r
565 The order of the boot options in BootOptionList and in the UEFI BootOrder\r
566 global variable are kept coherent until the user confirm his reordering (ie:\r
567 he does not exit by pressing escape).\r
568\r
569 @param[in] BootOptionsList List of the boot devices constructed in\r
570 BootMenuMain()\r
571\r
572 @retval EFI_SUCCESS No error encountered.\r
573 @retval !EFI_SUCCESS An error has occured either in the selection of the\r
574 boot option to move or while interacting with the user.\r
575\r
576**/\r
577STATIC\r
578EFI_STATUS\r
579BootMenuReorderBootOptions (\r
580 IN LIST_ENTRY *BootOptionsList\r
581 )\r
582{\r
583 EFI_STATUS Status;\r
584 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;\r
585 LIST_ENTRY *SelectedEntry;\r
586 LIST_ENTRY *PrevEntry;\r
587 BOOLEAN Move;\r
588 BOOLEAN Save;\r
589 BOOLEAN Cancel;\r
590 UINTN WaitIndex;\r
591 EFI_INPUT_KEY Key;\r
592 LIST_ENTRY *SecondEntry;\r
593 UINTN BootOrderSize;\r
594 UINT16 *BootOrder;\r
595 LIST_ENTRY *Entry;\r
596 UINTN Index;\r
597\r
598 DisplayBootOptions (BootOptionsList);\r
599\r
600 // Ask to select the boot option to move\r
601 while (TRUE) {\r
602 Status = SelectBootOption (BootOptionsList, MOVE_BOOT_ENTRY, &BootOptionEntry);\r
603 if (EFI_ERROR (Status)) {\r
604 goto ErrorExit;\r
605 }\r
606\r
607 SelectedEntry = &BootOptionEntry->Link;\r
749d91f7 608 SecondEntry = NULL;\r
019680b3
RC
609 // Note down the previous entry in the list to be able to cancel changes\r
610 PrevEntry = GetPreviousNode (BootOptionsList, SelectedEntry);\r
611\r
612 // Start of interaction\r
613 while (TRUE) {\r
614 Print (\r
615 L"* Use up/down arrows to move the entry '%s'",\r
616 BootOptionEntry->BdsLoadOption->Description\r
617 );\r
618\r
619 // Wait for a move, save or cancel request\r
620 Move = FALSE;\r
621 Save = FALSE;\r
622 Cancel = FALSE;\r
623 do {\r
624 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);\r
625 if (!EFI_ERROR (Status)) {\r
626 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
627 }\r
628 if (EFI_ERROR (Status)) {\r
629 Print (L"\n");\r
630 goto ErrorExit;\r
631 }\r
632\r
633 switch (Key.ScanCode) {\r
634 case SCAN_NULL:\r
635 Save = (Key.UnicodeChar == CHAR_LINEFEED) ||\r
636 (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) ||\r
637 (Key.UnicodeChar == 0x7f);\r
638 break;\r
639\r
640 case SCAN_UP:\r
641 SecondEntry = GetPreviousNode (BootOptionsList, SelectedEntry);\r
642 Move = SecondEntry != BootOptionsList;\r
643 break;\r
644\r
645 case SCAN_DOWN:\r
646 SecondEntry = GetNextNode (BootOptionsList, SelectedEntry);\r
647 Move = SecondEntry != BootOptionsList;\r
648 break;\r
649\r
650 case SCAN_ESC:\r
651 Cancel = TRUE;\r
652 break;\r
653 }\r
654 } while ((!Move) && (!Save) && (!Cancel));\r
655\r
656 if (Move) {\r
749d91f7
HL
657 if ((SelectedEntry != NULL) && (SecondEntry != NULL)) {\r
658 SwapListEntries (SelectedEntry, SecondEntry);\r
659 }\r
019680b3
RC
660 } else {\r
661 if (Save) {\r
662 Status = GetGlobalEnvironmentVariable (\r
663 L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder\r
664 );\r
665 BootOrderSize /= sizeof (UINT16);\r
666\r
667 if (!EFI_ERROR (Status)) {\r
668 // The order of the boot options in the 'BootOptionsList' is the\r
669 // new order that has been just defined by the user. Save this new\r
670 // order in "BootOrder" UEFI global variable.\r
671 Entry = GetFirstNode (BootOptionsList);\r
672 for (Index = 0; Index < BootOrderSize; Index++) {\r
673 BootOrder[Index] = (LOAD_OPTION_FROM_LINK (Entry))->LoadOptionIndex;\r
674 Entry = GetNextNode (BootOptionsList, Entry);\r
675 }\r
676 Status = gRT->SetVariable (\r
677 (CHAR16*)L"BootOrder",\r
678 &gEfiGlobalVariableGuid,\r
679 EFI_VARIABLE_NON_VOLATILE |\r
680 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
681 EFI_VARIABLE_RUNTIME_ACCESS,\r
682 BootOrderSize * sizeof (UINT16),\r
683 BootOrder\r
684 );\r
685 FreePool (BootOrder);\r
686 }\r
687\r
688 if (EFI_ERROR (Status)) {\r
689 Print (L"\nAn error occurred, move not completed!\n");\r
690 Cancel = TRUE;\r
691 }\r
692 }\r
693\r
694 if (Cancel) {\r
695 //\r
696 // Restore initial position of the selected boot option\r
697 //\r
698 RemoveEntryList (SelectedEntry);\r
699 InsertHeadList (PrevEntry, SelectedEntry);\r
700 }\r
701 }\r
702\r
703 Print (L"\n");\r
704 DisplayBootOptions (BootOptionsList);\r
705 // Saved or cancelled, back to the choice of boot option to move\r
706 if (!Move) {\r
707 break;\r
708 }\r
709 }\r
710 }\r
711\r
712ErrorExit:\r
713 return Status ;\r
714}\r
715\r
0ae6a518
RC
716EFI_STATUS\r
717UpdateFdtPath (\r
718 IN LIST_ENTRY *BootOptionsList\r
719 )\r
720{\r
721 EFI_STATUS Status;\r
722 BDS_SUPPORTED_DEVICE *SupportedBootDevice;\r
723 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePathNodes;\r
724 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePath;\r
725 CHAR16 *FdtTextDevicePath;\r
726 EFI_PHYSICAL_ADDRESS FdtBlobBase;\r
727 UINTN FdtBlobSize;\r
728 UINTN NumPages;\r
729 EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase;\r
730\r
731 SupportedBootDevice = NULL;\r
732\r
733 Status = SelectBootDevice (&SupportedBootDevice);\r
734 if (EFI_ERROR (Status)) {\r
735 Status = EFI_ABORTED;\r
736 goto EXIT;\r
737 }\r
738\r
739 // Create the specific device path node\r
740 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNodes);\r
741 if (EFI_ERROR (Status)) {\r
742 Status = EFI_ABORTED;\r
743 goto EXIT;\r
744 }\r
745\r
746 if (FdtDevicePathNodes != NULL) {\r
747 Status = EFI_OUT_OF_RESOURCES;\r
748\r
749 FdtDevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNodes);\r
750 FreePool (FdtDevicePathNodes);\r
751 if (FdtDevicePath == NULL) {\r
752 goto EXIT;\r
753 }\r
754\r
755 FdtTextDevicePath = ConvertDevicePathToText (FdtDevicePath, TRUE, TRUE);\r
756 if (FdtTextDevicePath == NULL) {\r
757 goto EXIT;\r
758 }\r
759\r
760 Status = gRT->SetVariable (\r
761 (CHAR16*)L"Fdt",\r
762 &gFdtVariableGuid,\r
763 EFI_VARIABLE_RUNTIME_ACCESS |\r
764 EFI_VARIABLE_NON_VOLATILE |\r
765 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
766 StrSize (FdtTextDevicePath),\r
767 FdtTextDevicePath\r
768 );\r
769 ASSERT_EFI_ERROR (Status);\r
770 FreePool (FdtTextDevicePath);\r
771 } else {\r
772 Status = gRT->SetVariable (\r
773 (CHAR16*)L"Fdt",\r
774 &gFdtVariableGuid,\r
775 EFI_VARIABLE_RUNTIME_ACCESS |\r
776 EFI_VARIABLE_NON_VOLATILE |\r
777 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
778 0,\r
779 NULL\r
780 );\r
781 ASSERT_EFI_ERROR (Status);\r
782 return Status;\r
783 }\r
784\r
785 //\r
786 // Try to load FDT from the new EFI Device Path\r
787 //\r
788\r
789 //\r
790 // Load the FDT given its device path.\r
791 // This operation may fail if the device path is not supported.\r
792 //\r
793 FdtBlobBase = 0;\r
794 NumPages = 0;\r
795 Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);\r
796 FreePool (FdtDevicePath);\r
797\r
798 if (EFI_ERROR (Status)) {\r
799 goto EXIT_LOAD_FDT;\r
800 }\r
801\r
802 // Check the FDT header is valid. We only make this check in DEBUG mode in\r
803 // case the FDT header change on production device and this ASSERT() becomes\r
804 // not valid.\r
805 ASSERT (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) == 0);\r
806\r
807 //\r
808 // Ensure the Size of the Device Tree is smaller than the size of the read file\r
809 //\r
810 ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) <= FdtBlobSize);\r
811\r
812 //\r
813 // Store the FDT as Runtime Service Data to prevent the Kernel from\r
814 // overwritting its data.\r
815 //\r
816 NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize);\r
817 Status = gBS->AllocatePages (\r
818 AllocateAnyPages, EfiRuntimeServicesData,\r
819 NumPages, &FdtConfigurationTableBase\r
820 );\r
821 if (EFI_ERROR (Status)) {\r
822 goto EXIT_LOAD_FDT;\r
823 }\r
824 gBS->CopyMem (\r
825 (VOID*)(UINTN)FdtConfigurationTableBase,\r
826 (VOID*)(UINTN)FdtBlobBase,\r
827 FdtBlobSize\r
828 );\r
829\r
830 //\r
831 // Install the FDT into the Configuration Table\r
832 //\r
833 Status = gBS->InstallConfigurationTable (\r
834 &gFdtTableGuid,\r
835 (VOID*)(UINTN)FdtConfigurationTableBase\r
836 );\r
837 if (EFI_ERROR (Status)) {\r
838 gBS->FreePages (FdtConfigurationTableBase, NumPages);\r
839 }\r
840\r
841EXIT_LOAD_FDT:\r
842 if (EFI_ERROR (Status)) {\r
843 Print (L"\nWarning: Did not manage to install the new device tree. Try to restart the platform.\n");\r
844 }\r
845\r
846 if (FdtBlobBase != 0) {\r
847 gBS->FreePages (FdtBlobBase, NumPages);\r
848 }\r
849\r
850EXIT:\r
851 if (Status == EFI_ABORTED) {\r
852 Print (L"\n");\r
853 }\r
854\r
855 if (SupportedBootDevice != NULL) {\r
856 FreePool (SupportedBootDevice);\r
857 }\r
858\r
859 return Status;\r
860}\r
861\r
42de0937
RC
862/**\r
863 Set boot timeout\r
864\r
865 Ask for the boot timeout in seconds and if the input succeeds assign the\r
866 input value to the UEFI global variable "Timeout". This function is called\r
867 when the user selects the "Set Boot Timeout" of the boot manager menu.\r
868\r
869 @param[in] BootOptionsList List of the boot devices, not used here\r
870\r
871 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard\r
872 input and assigned to the UEFI "Timeout" global\r
873 variable\r
874 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global\r
875 variable "Timeout" has failed.\r
876**/\r
877EFI_STATUS\r
878STATIC\r
879BootMenuSetBootTimeout (\r
880 IN LIST_ENTRY *BootOptionsList\r
881 )\r
882{\r
883 EFI_STATUS Status;\r
884 UINTN Input;\r
885 UINT16 Timeout;\r
886\r
887 Print (L"Timeout duration (in seconds): ");\r
888 Status = GetHIInputInteger (&Input);\r
889 if (EFI_ERROR (Status)) {\r
890 Print (L"\n");\r
891 goto ErrorExit;\r
892 }\r
893\r
894 Timeout = Input;\r
895 Status = gRT->SetVariable (\r
896 (CHAR16*)L"Timeout",\r
897 &gEfiGlobalVariableGuid,\r
898 EFI_VARIABLE_NON_VOLATILE |\r
899 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
900 EFI_VARIABLE_RUNTIME_ACCESS,\r
901 sizeof (UINT16),\r
902 &Timeout\r
903 );\r
904 ASSERT_EFI_ERROR (Status);\r
905\r
906ErrorExit:\r
907 return Status;\r
908}\r
909\r
ea46ebbe 910struct BOOT_MANAGER_ENTRY {\r
911 CONST CHAR16* Description;\r
912 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
913} BootManagerEntries[] = {\r
914 { L"Add Boot Device Entry", BootMenuAddBootOption },\r
915 { L"Update Boot Device Entry", BootMenuUpdateBootOption },\r
916 { L"Remove Boot Device Entry", BootMenuRemoveBootOption },\r
019680b3 917 { L"Reorder Boot Device Entries", BootMenuReorderBootOptions },\r
0ae6a518 918 { L"Update FDT path", UpdateFdtPath },\r
42de0937 919 { L"Set Boot Timeout", BootMenuSetBootTimeout },\r
ea46ebbe 920};\r
921\r
922EFI_STATUS\r
923BootMenuManager (\r
924 IN LIST_ENTRY *BootOptionsList\r
925 )\r
926{\r
927 UINTN Index;\r
928 UINTN OptionSelected;\r
929 UINTN BootManagerEntryCount;\r
930 EFI_STATUS Status;\r
931\r
932 BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);\r
933\r
934 while (TRUE) {\r
935 // Display Boot Manager menu\r
936 for (Index = 0; Index < BootManagerEntryCount; Index++) {\r
937 Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);\r
938 }\r
939 Print(L"[%d] Return to main menu\n",Index+1);\r
940\r
941 // Select which entry to call\r
942 Print(L"Choice: ");\r
943 Status = GetHIInputInteger (&OptionSelected);\r
944 if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {\r
326d1df9 945 if (EFI_ERROR(Status)) {\r
946 Print(L"\n");\r
947 }\r
ea46ebbe 948 return EFI_SUCCESS;\r
949 } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {\r
ff7666c5 950 BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);\r
ea46ebbe 951 }\r
952 }\r
11c20f4e 953 // Should never go here\r
ea46ebbe 954}\r
955\r
956EFI_STATUS\r
8213627e 957BootShell (\r
ea46ebbe 958 IN LIST_ENTRY *BootOptionsList\r
959 )\r
960{\r
0c72676d
OM
961 EFI_STATUS Status;\r
962 EFI_DEVICE_PATH* EfiShellDevicePath;\r
ea46ebbe 963\r
0c72676d
OM
964 // Find the EFI Shell\r
965 Status = LocateEfiApplicationInFvByName (L"Shell", &EfiShellDevicePath);\r
ea46ebbe 966 if (Status == EFI_NOT_FOUND) {\r
967 Print (L"Error: EFI Application not found.\n");\r
0c72676d
OM
968 return Status;\r
969 } else if (EFI_ERROR (Status)) {\r
970 Print (L"Error: Status Code: 0x%X\n", (UINT32)Status);\r
971 return Status;\r
972 } else {\r
973 // Need to connect every drivers to ensure no dependencies are missing for the application\r
974 Status = BdsConnectAllDrivers ();\r
975 if (EFI_ERROR (Status)) {\r
976 DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n"));\r
977 return Status;\r
978 }\r
ea46ebbe 979\r
0c72676d
OM
980 return BdsStartEfiApplication (gImageHandle, EfiShellDevicePath, 0, NULL);\r
981 }\r
ea46ebbe 982}\r
983\r
984struct BOOT_MAIN_ENTRY {\r
985 CONST CHAR16* Description;\r
986 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
987} BootMainEntries[] = {\r
8213627e 988 { L"Shell", BootShell },\r
ea46ebbe 989 { L"Boot Manager", BootMenuManager },\r
990};\r
991\r
ea46ebbe 992EFI_STATUS\r
993BootMenuMain (\r
994 VOID\r
995 )\r
996{\r
2ccfb71e 997 LIST_ENTRY BootOptionsList;\r
998 UINTN OptionCount;\r
999 UINTN BootOptionCount;\r
1000 EFI_STATUS Status;\r
1001 LIST_ENTRY* Entry;\r
1002 BDS_LOAD_OPTION* BootOption;\r
1003 UINTN BootOptionSelected;\r
1004 UINTN Index;\r
1005 UINTN BootMainEntryCount;\r
5389972a 1006 BOOLEAN IsUnicode;\r
ea46ebbe 1007\r
5389972a 1008 BootOption = NULL;\r
ea46ebbe 1009 BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);\r
a6caee65 1010\r
5d9e9d1a
OM
1011 if (FeaturePcdGet (PcdBdsLinuxSupport)) {\r
1012 // Check Linux Loader is present\r
1013 Status = LocateEfiApplicationInFvByGuid (&mLinuxLoaderAppGuid, &mLinuxLoaderDevicePath);\r
1014 ASSERT_EFI_ERROR (Status);\r
1015 }\r
1016\r
ea46ebbe 1017 while (TRUE) {\r
a6e97d28 1018 // Get Boot#### list\r
1019 BootOptionList (&BootOptionsList);\r
1020\r
ea46ebbe 1021 OptionCount = 1;\r
1022\r
1023 // Display the Boot options\r
1024 for (Entry = GetFirstNode (&BootOptionsList);\r
1025 !IsNull (&BootOptionsList,Entry);\r
1026 Entry = GetNextNode (&BootOptionsList,Entry)\r
1027 )\r
1028 {\r
1029 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
1030\r
ff7666c5 1031 Print(L"[%d] %s\n", OptionCount, BootOption->Description);\r
ea46ebbe 1032\r
1033 DEBUG_CODE_BEGIN();\r
1034 CHAR16* DevicePathTxt;\r
1035 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
1036\r
ff7666c5 1037 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
aa95e2f7 1038 if (EFI_ERROR(Status)) {\r
1039 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)\r
1040 DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));\r
1041 return Status;\r
1042 }\r
ff7666c5 1043 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE);\r
ea46ebbe 1044\r
1045 Print(L"\t- %s\n",DevicePathTxt);\r
2ccfb71e 1046\r
8b129b7b 1047 if (BootOption->OptionalData != NULL) {\r
5389972a
OM
1048 if (IsPrintableString (BootOption->OptionalData, &IsUnicode)) {\r
1049 if (IsUnicode) {\r
1050 Print (L"\t- Arguments: %s\n", BootOption->OptionalData);\r
1051 } else {\r
1052 AsciiPrint ("\t- Arguments: %a\n", BootOption->OptionalData);\r
1053 }\r
1054 }\r
ea46ebbe 1055 }\r
ea46ebbe 1056 FreePool(DevicePathTxt);\r
1057 DEBUG_CODE_END();\r
1058\r
1059 OptionCount++;\r
1060 }\r
1061 BootOptionCount = OptionCount-1;\r
1062\r
1063 // Display the hardcoded Boot entries\r
1064 for (Index = 0; Index < BootMainEntryCount; Index++) {\r
1065 Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);\r
1066 OptionCount++;\r
1067 }\r
1068\r
1069 // Request the boot entry from the user\r
1070 BootOptionSelected = 0;\r
1071 while (BootOptionSelected == 0) {\r
1072 Print(L"Start: ");\r
1073 Status = GetHIInputInteger (&BootOptionSelected);\r
1074 if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {\r
1075 Print(L"Invalid input (max %d)\n",(OptionCount-1));\r
1076 BootOptionSelected = 0;\r
1077 }\r
1078 }\r
1079\r
1080 // Start the selected entry\r
1081 if (BootOptionSelected > BootOptionCount) {\r
1082 // Start the hardcoded entry\r
1083 Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);\r
1084 } else {\r
1085 // Find the selected entry from the Boot#### list\r
1086 Index = 1;\r
1087 for (Entry = GetFirstNode (&BootOptionsList);\r
1088 !IsNull (&BootOptionsList,Entry);\r
1089 Entry = GetNextNode (&BootOptionsList,Entry)\r
1090 )\r
1091 {\r
1092 if (Index == BootOptionSelected) {\r
1093 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
1094 break;\r
1095 }\r
1096 Index++;\r
1097 }\r
1098\r
1099 Status = BootOptionStart (BootOption);\r
1100 }\r
1101 }\r
11c20f4e 1102 // Should never go here\r
ea46ebbe 1103}\r