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