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