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