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