]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Bds/BootMenu.c
ArmPkg: Remove PCD declarations linked to the ARM BDS Linux Loader
[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
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
889ac6a8 284 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application or the kernel", &DevicePathNodes);\r
ea46ebbe 285 if (EFI_ERROR(Status)) {\r
286 Status = EFI_ABORTED;\r
287 goto EXIT;\r
288 }\r
ecc62d13 289 // Append the Device Path to the selected device path\r
290 DevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNodes);\r
291 if (DevicePath == NULL) {\r
292 Status = EFI_OUT_OF_RESOURCES;\r
293 goto EXIT;\r
294 }\r
ea46ebbe 295\r
8b129b7b
OM
296 Print (L"Arguments to pass to the EFI Application: ");\r
297 Status = GetHIInputStr (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
298 if (EFI_ERROR (Status)) {\r
299 Status = EFI_ABORTED;\r
300 goto EXIT;\r
55a9f75d
OM
301 }\r
302\r
8b129b7b
OM
303 OptionalData = (UINT8*)CmdLine;\r
304 OptionalDataSize = StrSize (CmdLine);\r
ea46ebbe 305\r
306 Print(L"Description for this new Entry: ");\r
74b96132 307 Status = GetHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
ea46ebbe 308 if (EFI_ERROR(Status)) {\r
309 Status = EFI_ABORTED;\r
310 goto FREE_DEVICE_PATH;\r
311 }\r
312\r
ea46ebbe 313 // Create new entry\r
a6e97d28 314 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY));\r
8b129b7b 315 Status = BootOptionCreate (Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize, &BdsLoadOptionEntry->BdsLoadOption);\r
ea46ebbe 316 if (!EFI_ERROR(Status)) {\r
a6e97d28 317 InsertTailList (BootOptionsList, &BdsLoadOptionEntry->Link);\r
ea46ebbe 318 }\r
319\r
ea46ebbe 320FREE_DEVICE_PATH:\r
321 FreePool (DevicePath);\r
322\r
323EXIT:\r
656416bc 324 if (Status == EFI_ABORTED) {\r
325 Print(L"\n");\r
326 }\r
327 FreePool(SupportedBootDevice);\r
ea46ebbe 328 return Status;\r
329}\r
330\r
ea46ebbe 331EFI_STATUS\r
332BootMenuRemoveBootOption (\r
333 IN LIST_ENTRY *BootOptionsList\r
334 )\r
335{\r
a6e97d28 336 EFI_STATUS Status;\r
337 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;\r
ea46ebbe 338\r
019680b3
RC
339 DisplayBootOptions (BootOptionsList);\r
340 Status = SelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, &BootOptionEntry);\r
341 if (EFI_ERROR (Status)) {\r
ea46ebbe 342 return Status;\r
343 }\r
344\r
a6e97d28 345 // If the Boot Option was attached to a list remove it\r
346 if (!IsListEmpty (&BootOptionEntry->Link)) {\r
347 // Remove the entry from the list\r
348 RemoveEntryList (&BootOptionEntry->Link);\r
349 }\r
350\r
ea46ebbe 351 // Delete the BDS Load option structures\r
a6e97d28 352 BootOptionDelete (BootOptionEntry->BdsLoadOption);\r
ea46ebbe 353\r
354 return EFI_SUCCESS;\r
355}\r
356\r
357EFI_STATUS\r
358BootMenuUpdateBootOption (\r
359 IN LIST_ENTRY *BootOptionsList\r
360 )\r
361{\r
2ccfb71e 362 EFI_STATUS Status;\r
a6e97d28 363 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;\r
2ccfb71e 364 BDS_LOAD_OPTION *BootOption;\r
365 BDS_LOAD_OPTION_SUPPORT* DeviceSupport;\r
74b96132 366 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
2ccfb71e 367 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];\r
3b3b72d6 368 CHAR16 UnicodeCmdLine[BOOT_DEVICE_OPTION_MAX];\r
14238a61 369 EFI_DEVICE_PATH *DevicePath;\r
90a44ec4
OM
370 UINT8* OptionalData;\r
371 UINTN OptionalDataSize;\r
3b3b72d6
OM
372 BOOLEAN IsPrintable;\r
373 BOOLEAN IsUnicode;\r
ea46ebbe 374\r
019680b3
RC
375 DisplayBootOptions (BootOptionsList);\r
376 Status = SelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry);\r
377 if (EFI_ERROR (Status)) {\r
ea46ebbe 378 return Status;\r
379 }\r
a6e97d28 380 BootOption = BootOptionEntry->BdsLoadOption;\r
ea46ebbe 381\r
382 // Get the device support for this Boot Option\r
22a262c8 383 Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport);\r
ea46ebbe 384 if (EFI_ERROR(Status)) {\r
ff7666c5 385 Print(L"Not possible to retrieve the supported device for the update\n");\r
ea46ebbe 386 return EFI_UNSUPPORTED;\r
387 }\r
388\r
889ac6a8 389 Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath);\r
ea46ebbe 390 if (EFI_ERROR(Status)) {\r
391 Status = EFI_ABORTED;\r
392 goto EXIT;\r
393 }\r
394\r
8b129b7b 395 Print (L"Arguments to pass to the EFI Application: ");\r
22a262c8 396\r
8b129b7b
OM
397 if (BootOption->OptionalDataSize > 0) {\r
398 IsPrintable = IsPrintableString (BootOption->OptionalData, &IsUnicode);\r
399 if (IsPrintable) {\r
400 //\r
401 // The size in bytes of the string, final zero included, should\r
402 // be equal to or at least lower than "BootOption->OptionalDataSize"\r
403 // and the "IsPrintableString()" has already tested that the length\r
404 // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,\r
405 // final '\0' included. We can thus copy the string for editing\r
406 // using "CopyMem()". Furthermore, note that in the case of an Unicode\r
407 // string "StrnCpy()" and "StrCpy()" can not be used to copy the\r
408 // string because the data pointed to by "BootOption->OptionalData"\r
409 // is not necessarily 2-byte aligned.\r
410 //\r
411 if (IsUnicode) {\r
412 CopyMem (\r
413 UnicodeCmdLine, BootOption->OptionalData,\r
414 MIN (sizeof (UnicodeCmdLine),\r
415 BootOption->OptionalDataSize)\r
416 );\r
22a262c8 417 } else {\r
8b129b7b
OM
418 CopyMem (\r
419 CmdLine, BootOption->OptionalData,\r
420 MIN (sizeof (CmdLine),\r
421 BootOption->OptionalDataSize)\r
422 );\r
3e710183 423 }\r
656416bc 424 }\r
2ccfb71e 425 } else {\r
8b129b7b
OM
426 UnicodeCmdLine[0] = L'\0';\r
427 IsPrintable = TRUE;\r
428 IsUnicode = TRUE;\r
429 }\r
3b3b72d6 430\r
8b129b7b
OM
431 // We do not request arguments for OptionalData that cannot be printed\r
432 if (IsPrintable) {\r
433 if (IsUnicode) {\r
434 Status = EditHIInputStr (UnicodeCmdLine, BOOT_DEVICE_OPTION_MAX);\r
435 if (EFI_ERROR (Status)) {\r
436 Status = EFI_ABORTED;\r
437 goto FREE_DEVICE_PATH;\r
3b3b72d6 438 }\r
3b3b72d6 439\r
8b129b7b
OM
440 OptionalData = (UINT8*)UnicodeCmdLine;\r
441 OptionalDataSize = StrSize (UnicodeCmdLine);\r
3b3b72d6 442 } else {\r
8b129b7b
OM
443 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
444 if (EFI_ERROR (Status)) {\r
445 Status = EFI_ABORTED;\r
446 goto FREE_DEVICE_PATH;\r
447 }\r
448\r
449 OptionalData = (UINT8*)CmdLine;\r
450 OptionalDataSize = AsciiStrSize (CmdLine);\r
3b3b72d6 451 }\r
8b129b7b
OM
452 } else {\r
453 // We keep the former OptionalData\r
454 OptionalData = BootOption->OptionalData;\r
455 OptionalDataSize = BootOption->OptionalDataSize;\r
ea46ebbe 456 }\r
457\r
458 Print(L"Description for this new Entry: ");\r
3e710183 459 StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX);\r
74b96132 460 Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
ea46ebbe 461 if (EFI_ERROR(Status)) {\r
462 Status = EFI_ABORTED;\r
463 goto FREE_DEVICE_PATH;\r
464 }\r
465\r
ea46ebbe 466 // Update the entry\r
8b129b7b 467 Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, OptionalData, OptionalDataSize);\r
ea46ebbe 468\r
ea46ebbe 469FREE_DEVICE_PATH:\r
470 FreePool (DevicePath);\r
471\r
472EXIT:\r
326d1df9 473 if (Status == EFI_ABORTED) {\r
474 Print(L"\n");\r
475 }\r
ea46ebbe 476 return Status;\r
477}\r
478\r
019680b3
RC
479/**\r
480 Reorder boot options\r
481\r
482 Ask for the boot option to move and then move it when up or down arrows\r
483 are pressed. This function is called when the user selects the "Reorder Boot\r
484 Device Entries" entry in the boot manager menu.\r
485 The order of the boot options in BootOptionList and in the UEFI BootOrder\r
486 global variable are kept coherent until the user confirm his reordering (ie:\r
487 he does not exit by pressing escape).\r
488\r
489 @param[in] BootOptionsList List of the boot devices constructed in\r
490 BootMenuMain()\r
491\r
492 @retval EFI_SUCCESS No error encountered.\r
493 @retval !EFI_SUCCESS An error has occured either in the selection of the\r
494 boot option to move or while interacting with the user.\r
495\r
496**/\r
497STATIC\r
498EFI_STATUS\r
499BootMenuReorderBootOptions (\r
500 IN LIST_ENTRY *BootOptionsList\r
501 )\r
502{\r
503 EFI_STATUS Status;\r
504 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;\r
505 LIST_ENTRY *SelectedEntry;\r
506 LIST_ENTRY *PrevEntry;\r
507 BOOLEAN Move;\r
508 BOOLEAN Save;\r
509 BOOLEAN Cancel;\r
510 UINTN WaitIndex;\r
511 EFI_INPUT_KEY Key;\r
512 LIST_ENTRY *SecondEntry;\r
513 UINTN BootOrderSize;\r
514 UINT16 *BootOrder;\r
515 LIST_ENTRY *Entry;\r
516 UINTN Index;\r
517\r
518 DisplayBootOptions (BootOptionsList);\r
519\r
520 // Ask to select the boot option to move\r
521 while (TRUE) {\r
522 Status = SelectBootOption (BootOptionsList, MOVE_BOOT_ENTRY, &BootOptionEntry);\r
523 if (EFI_ERROR (Status)) {\r
524 goto ErrorExit;\r
525 }\r
526\r
527 SelectedEntry = &BootOptionEntry->Link;\r
749d91f7 528 SecondEntry = NULL;\r
019680b3
RC
529 // Note down the previous entry in the list to be able to cancel changes\r
530 PrevEntry = GetPreviousNode (BootOptionsList, SelectedEntry);\r
531\r
532 // Start of interaction\r
533 while (TRUE) {\r
534 Print (\r
535 L"* Use up/down arrows to move the entry '%s'",\r
536 BootOptionEntry->BdsLoadOption->Description\r
537 );\r
538\r
539 // Wait for a move, save or cancel request\r
540 Move = FALSE;\r
541 Save = FALSE;\r
542 Cancel = FALSE;\r
543 do {\r
544 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);\r
545 if (!EFI_ERROR (Status)) {\r
546 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
547 }\r
548 if (EFI_ERROR (Status)) {\r
549 Print (L"\n");\r
550 goto ErrorExit;\r
551 }\r
552\r
553 switch (Key.ScanCode) {\r
554 case SCAN_NULL:\r
555 Save = (Key.UnicodeChar == CHAR_LINEFEED) ||\r
556 (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) ||\r
557 (Key.UnicodeChar == 0x7f);\r
558 break;\r
559\r
560 case SCAN_UP:\r
561 SecondEntry = GetPreviousNode (BootOptionsList, SelectedEntry);\r
562 Move = SecondEntry != BootOptionsList;\r
563 break;\r
564\r
565 case SCAN_DOWN:\r
566 SecondEntry = GetNextNode (BootOptionsList, SelectedEntry);\r
567 Move = SecondEntry != BootOptionsList;\r
568 break;\r
569\r
570 case SCAN_ESC:\r
571 Cancel = TRUE;\r
572 break;\r
573 }\r
574 } while ((!Move) && (!Save) && (!Cancel));\r
575\r
576 if (Move) {\r
749d91f7
HL
577 if ((SelectedEntry != NULL) && (SecondEntry != NULL)) {\r
578 SwapListEntries (SelectedEntry, SecondEntry);\r
579 }\r
019680b3
RC
580 } else {\r
581 if (Save) {\r
582 Status = GetGlobalEnvironmentVariable (\r
583 L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder\r
584 );\r
585 BootOrderSize /= sizeof (UINT16);\r
586\r
587 if (!EFI_ERROR (Status)) {\r
588 // The order of the boot options in the 'BootOptionsList' is the\r
589 // new order that has been just defined by the user. Save this new\r
590 // order in "BootOrder" UEFI global variable.\r
591 Entry = GetFirstNode (BootOptionsList);\r
592 for (Index = 0; Index < BootOrderSize; Index++) {\r
593 BootOrder[Index] = (LOAD_OPTION_FROM_LINK (Entry))->LoadOptionIndex;\r
594 Entry = GetNextNode (BootOptionsList, Entry);\r
595 }\r
596 Status = gRT->SetVariable (\r
597 (CHAR16*)L"BootOrder",\r
598 &gEfiGlobalVariableGuid,\r
599 EFI_VARIABLE_NON_VOLATILE |\r
600 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
601 EFI_VARIABLE_RUNTIME_ACCESS,\r
602 BootOrderSize * sizeof (UINT16),\r
603 BootOrder\r
604 );\r
605 FreePool (BootOrder);\r
606 }\r
607\r
608 if (EFI_ERROR (Status)) {\r
609 Print (L"\nAn error occurred, move not completed!\n");\r
610 Cancel = TRUE;\r
611 }\r
612 }\r
613\r
614 if (Cancel) {\r
615 //\r
616 // Restore initial position of the selected boot option\r
617 //\r
618 RemoveEntryList (SelectedEntry);\r
619 InsertHeadList (PrevEntry, SelectedEntry);\r
620 }\r
621 }\r
622\r
623 Print (L"\n");\r
624 DisplayBootOptions (BootOptionsList);\r
625 // Saved or cancelled, back to the choice of boot option to move\r
626 if (!Move) {\r
627 break;\r
628 }\r
629 }\r
630 }\r
631\r
632ErrorExit:\r
633 return Status ;\r
634}\r
635\r
0ae6a518
RC
636EFI_STATUS\r
637UpdateFdtPath (\r
638 IN LIST_ENTRY *BootOptionsList\r
639 )\r
640{\r
641 EFI_STATUS Status;\r
642 BDS_SUPPORTED_DEVICE *SupportedBootDevice;\r
643 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePathNodes;\r
644 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePath;\r
645 CHAR16 *FdtTextDevicePath;\r
646 EFI_PHYSICAL_ADDRESS FdtBlobBase;\r
647 UINTN FdtBlobSize;\r
648 UINTN NumPages;\r
649 EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase;\r
650\r
651 SupportedBootDevice = NULL;\r
652\r
653 Status = SelectBootDevice (&SupportedBootDevice);\r
654 if (EFI_ERROR (Status)) {\r
655 Status = EFI_ABORTED;\r
656 goto EXIT;\r
657 }\r
658\r
659 // Create the specific device path node\r
660 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNodes);\r
661 if (EFI_ERROR (Status)) {\r
662 Status = EFI_ABORTED;\r
663 goto EXIT;\r
664 }\r
665\r
666 if (FdtDevicePathNodes != NULL) {\r
667 Status = EFI_OUT_OF_RESOURCES;\r
668\r
669 FdtDevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNodes);\r
670 FreePool (FdtDevicePathNodes);\r
671 if (FdtDevicePath == NULL) {\r
672 goto EXIT;\r
673 }\r
674\r
675 FdtTextDevicePath = ConvertDevicePathToText (FdtDevicePath, TRUE, TRUE);\r
676 if (FdtTextDevicePath == NULL) {\r
677 goto EXIT;\r
678 }\r
679\r
680 Status = gRT->SetVariable (\r
681 (CHAR16*)L"Fdt",\r
682 &gFdtVariableGuid,\r
683 EFI_VARIABLE_RUNTIME_ACCESS |\r
684 EFI_VARIABLE_NON_VOLATILE |\r
685 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
686 StrSize (FdtTextDevicePath),\r
687 FdtTextDevicePath\r
688 );\r
689 ASSERT_EFI_ERROR (Status);\r
690 FreePool (FdtTextDevicePath);\r
691 } else {\r
692 Status = gRT->SetVariable (\r
693 (CHAR16*)L"Fdt",\r
694 &gFdtVariableGuid,\r
695 EFI_VARIABLE_RUNTIME_ACCESS |\r
696 EFI_VARIABLE_NON_VOLATILE |\r
697 EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
698 0,\r
699 NULL\r
700 );\r
701 ASSERT_EFI_ERROR (Status);\r
702 return Status;\r
703 }\r
704\r
705 //\r
706 // Try to load FDT from the new EFI Device Path\r
707 //\r
708\r
709 //\r
710 // Load the FDT given its device path.\r
711 // This operation may fail if the device path is not supported.\r
712 //\r
713 FdtBlobBase = 0;\r
714 NumPages = 0;\r
715 Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);\r
716 FreePool (FdtDevicePath);\r
717\r
718 if (EFI_ERROR (Status)) {\r
719 goto EXIT_LOAD_FDT;\r
720 }\r
721\r
722 // Check the FDT header is valid. We only make this check in DEBUG mode in\r
723 // case the FDT header change on production device and this ASSERT() becomes\r
724 // not valid.\r
725 ASSERT (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) == 0);\r
726\r
727 //\r
728 // Ensure the Size of the Device Tree is smaller than the size of the read file\r
729 //\r
730 ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) <= FdtBlobSize);\r
731\r
732 //\r
733 // Store the FDT as Runtime Service Data to prevent the Kernel from\r
734 // overwritting its data.\r
735 //\r
736 NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize);\r
737 Status = gBS->AllocatePages (\r
738 AllocateAnyPages, EfiRuntimeServicesData,\r
739 NumPages, &FdtConfigurationTableBase\r
740 );\r
741 if (EFI_ERROR (Status)) {\r
742 goto EXIT_LOAD_FDT;\r
743 }\r
744 gBS->CopyMem (\r
745 (VOID*)(UINTN)FdtConfigurationTableBase,\r
746 (VOID*)(UINTN)FdtBlobBase,\r
747 FdtBlobSize\r
748 );\r
749\r
750 //\r
751 // Install the FDT into the Configuration Table\r
752 //\r
753 Status = gBS->InstallConfigurationTable (\r
754 &gFdtTableGuid,\r
755 (VOID*)(UINTN)FdtConfigurationTableBase\r
756 );\r
757 if (EFI_ERROR (Status)) {\r
758 gBS->FreePages (FdtConfigurationTableBase, NumPages);\r
759 }\r
760\r
761EXIT_LOAD_FDT:\r
762 if (EFI_ERROR (Status)) {\r
763 Print (L"\nWarning: Did not manage to install the new device tree. Try to restart the platform.\n");\r
764 }\r
765\r
766 if (FdtBlobBase != 0) {\r
767 gBS->FreePages (FdtBlobBase, NumPages);\r
768 }\r
769\r
770EXIT:\r
771 if (Status == EFI_ABORTED) {\r
772 Print (L"\n");\r
773 }\r
774\r
775 if (SupportedBootDevice != NULL) {\r
776 FreePool (SupportedBootDevice);\r
777 }\r
778\r
779 return Status;\r
780}\r
781\r
42de0937
RC
782/**\r
783 Set boot timeout\r
784\r
785 Ask for the boot timeout in seconds and if the input succeeds assign the\r
786 input value to the UEFI global variable "Timeout". This function is called\r
787 when the user selects the "Set Boot Timeout" of the boot manager menu.\r
788\r
789 @param[in] BootOptionsList List of the boot devices, not used here\r
790\r
791 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard\r
792 input and assigned to the UEFI "Timeout" global\r
793 variable\r
794 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global\r
795 variable "Timeout" has failed.\r
796**/\r
797EFI_STATUS\r
798STATIC\r
799BootMenuSetBootTimeout (\r
800 IN LIST_ENTRY *BootOptionsList\r
801 )\r
802{\r
803 EFI_STATUS Status;\r
804 UINTN Input;\r
805 UINT16 Timeout;\r
806\r
807 Print (L"Timeout duration (in seconds): ");\r
808 Status = GetHIInputInteger (&Input);\r
809 if (EFI_ERROR (Status)) {\r
810 Print (L"\n");\r
811 goto ErrorExit;\r
812 }\r
813\r
814 Timeout = Input;\r
815 Status = gRT->SetVariable (\r
816 (CHAR16*)L"Timeout",\r
817 &gEfiGlobalVariableGuid,\r
818 EFI_VARIABLE_NON_VOLATILE |\r
819 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
820 EFI_VARIABLE_RUNTIME_ACCESS,\r
821 sizeof (UINT16),\r
822 &Timeout\r
823 );\r
824 ASSERT_EFI_ERROR (Status);\r
825\r
826ErrorExit:\r
827 return Status;\r
828}\r
829\r
ea46ebbe 830struct BOOT_MANAGER_ENTRY {\r
831 CONST CHAR16* Description;\r
832 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
833} BootManagerEntries[] = {\r
834 { L"Add Boot Device Entry", BootMenuAddBootOption },\r
835 { L"Update Boot Device Entry", BootMenuUpdateBootOption },\r
836 { L"Remove Boot Device Entry", BootMenuRemoveBootOption },\r
019680b3 837 { L"Reorder Boot Device Entries", BootMenuReorderBootOptions },\r
0ae6a518 838 { L"Update FDT path", UpdateFdtPath },\r
42de0937 839 { L"Set Boot Timeout", BootMenuSetBootTimeout },\r
ea46ebbe 840};\r
841\r
842EFI_STATUS\r
843BootMenuManager (\r
844 IN LIST_ENTRY *BootOptionsList\r
845 )\r
846{\r
847 UINTN Index;\r
848 UINTN OptionSelected;\r
849 UINTN BootManagerEntryCount;\r
850 EFI_STATUS Status;\r
851\r
852 BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);\r
853\r
854 while (TRUE) {\r
855 // Display Boot Manager menu\r
856 for (Index = 0; Index < BootManagerEntryCount; Index++) {\r
857 Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);\r
858 }\r
859 Print(L"[%d] Return to main menu\n",Index+1);\r
860\r
861 // Select which entry to call\r
862 Print(L"Choice: ");\r
863 Status = GetHIInputInteger (&OptionSelected);\r
864 if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {\r
326d1df9 865 if (EFI_ERROR(Status)) {\r
866 Print(L"\n");\r
867 }\r
ea46ebbe 868 return EFI_SUCCESS;\r
869 } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {\r
ff7666c5 870 BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);\r
ea46ebbe 871 }\r
872 }\r
11c20f4e 873 // Should never go here\r
ea46ebbe 874}\r
875\r
876EFI_STATUS\r
8213627e 877BootShell (\r
ea46ebbe 878 IN LIST_ENTRY *BootOptionsList\r
879 )\r
880{\r
0c72676d
OM
881 EFI_STATUS Status;\r
882 EFI_DEVICE_PATH* EfiShellDevicePath;\r
ea46ebbe 883\r
0c72676d
OM
884 // Find the EFI Shell\r
885 Status = LocateEfiApplicationInFvByName (L"Shell", &EfiShellDevicePath);\r
ea46ebbe 886 if (Status == EFI_NOT_FOUND) {\r
887 Print (L"Error: EFI Application not found.\n");\r
0c72676d
OM
888 return Status;\r
889 } else if (EFI_ERROR (Status)) {\r
890 Print (L"Error: Status Code: 0x%X\n", (UINT32)Status);\r
891 return Status;\r
892 } else {\r
893 // Need to connect every drivers to ensure no dependencies are missing for the application\r
894 Status = BdsConnectAllDrivers ();\r
895 if (EFI_ERROR (Status)) {\r
896 DEBUG ((EFI_D_ERROR, "FAIL to connect all drivers\n"));\r
897 return Status;\r
898 }\r
ea46ebbe 899\r
0c72676d
OM
900 return BdsStartEfiApplication (gImageHandle, EfiShellDevicePath, 0, NULL);\r
901 }\r
ea46ebbe 902}\r
903\r
904struct BOOT_MAIN_ENTRY {\r
905 CONST CHAR16* Description;\r
906 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
907} BootMainEntries[] = {\r
8213627e 908 { L"Shell", BootShell },\r
ea46ebbe 909 { L"Boot Manager", BootMenuManager },\r
910};\r
911\r
912\r
913EFI_STATUS\r
914BootMenuMain (\r
915 VOID\r
916 )\r
917{\r
2ccfb71e 918 LIST_ENTRY BootOptionsList;\r
919 UINTN OptionCount;\r
920 UINTN BootOptionCount;\r
921 EFI_STATUS Status;\r
922 LIST_ENTRY* Entry;\r
923 BDS_LOAD_OPTION* BootOption;\r
924 UINTN BootOptionSelected;\r
925 UINTN Index;\r
926 UINTN BootMainEntryCount;\r
5389972a 927 BOOLEAN IsUnicode;\r
ea46ebbe 928\r
5389972a 929 BootOption = NULL;\r
ea46ebbe 930 BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);\r
a6caee65 931\r
ea46ebbe 932 while (TRUE) {\r
a6e97d28 933 // Get Boot#### list\r
934 BootOptionList (&BootOptionsList);\r
935\r
ea46ebbe 936 OptionCount = 1;\r
937\r
938 // Display the Boot options\r
939 for (Entry = GetFirstNode (&BootOptionsList);\r
940 !IsNull (&BootOptionsList,Entry);\r
941 Entry = GetNextNode (&BootOptionsList,Entry)\r
942 )\r
943 {\r
944 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
945\r
ff7666c5 946 Print(L"[%d] %s\n", OptionCount, BootOption->Description);\r
ea46ebbe 947\r
948 DEBUG_CODE_BEGIN();\r
949 CHAR16* DevicePathTxt;\r
950 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
951\r
ff7666c5 952 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
aa95e2f7 953 if (EFI_ERROR(Status)) {\r
954 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)\r
955 DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));\r
956 return Status;\r
957 }\r
ff7666c5 958 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE);\r
ea46ebbe 959\r
960 Print(L"\t- %s\n",DevicePathTxt);\r
2ccfb71e 961\r
8b129b7b 962 if (BootOption->OptionalData != NULL) {\r
5389972a
OM
963 if (IsPrintableString (BootOption->OptionalData, &IsUnicode)) {\r
964 if (IsUnicode) {\r
965 Print (L"\t- Arguments: %s\n", BootOption->OptionalData);\r
966 } else {\r
967 AsciiPrint ("\t- Arguments: %a\n", BootOption->OptionalData);\r
968 }\r
969 }\r
ea46ebbe 970 }\r
ea46ebbe 971 FreePool(DevicePathTxt);\r
972 DEBUG_CODE_END();\r
973\r
974 OptionCount++;\r
975 }\r
976 BootOptionCount = OptionCount-1;\r
977\r
978 // Display the hardcoded Boot entries\r
979 for (Index = 0; Index < BootMainEntryCount; Index++) {\r
980 Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);\r
981 OptionCount++;\r
982 }\r
983\r
984 // Request the boot entry from the user\r
985 BootOptionSelected = 0;\r
986 while (BootOptionSelected == 0) {\r
987 Print(L"Start: ");\r
988 Status = GetHIInputInteger (&BootOptionSelected);\r
989 if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {\r
990 Print(L"Invalid input (max %d)\n",(OptionCount-1));\r
991 BootOptionSelected = 0;\r
992 }\r
993 }\r
994\r
995 // Start the selected entry\r
996 if (BootOptionSelected > BootOptionCount) {\r
997 // Start the hardcoded entry\r
998 Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);\r
999 } else {\r
1000 // Find the selected entry from the Boot#### list\r
1001 Index = 1;\r
1002 for (Entry = GetFirstNode (&BootOptionsList);\r
1003 !IsNull (&BootOptionsList,Entry);\r
1004 Entry = GetNextNode (&BootOptionsList,Entry)\r
1005 )\r
1006 {\r
1007 if (Index == BootOptionSelected) {\r
1008 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
1009 break;\r
1010 }\r
1011 Index++;\r
1012 }\r
1013\r
1014 Status = BootOptionStart (BootOption);\r
1015 }\r
1016 }\r
11c20f4e 1017 // Should never go here\r
ea46ebbe 1018}\r