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