]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - ArmPlatformPkg/Bds/BootMenu.c
ArmPlatformPkg/Bds: Corrected boot type detection
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootMenu.c
... / ...
CommitLineData
1/** @file\r
2*\r
3* Copyright (c) 2011 - 2014, ARM Limited. All rights reserved.\r
4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "BdsInternal.h"\r
16\r
17#include <Guid/ArmGlobalVariableHob.h>\r
18\r
19extern EFI_HANDLE mImageHandle;\r
20extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;\r
21\r
22\r
23EFI_STATUS\r
24SelectBootDevice (\r
25 OUT BDS_SUPPORTED_DEVICE** SupportedBootDevice\r
26 )\r
27{\r
28 EFI_STATUS Status;\r
29 LIST_ENTRY SupportedDeviceList;\r
30 UINTN SupportedDeviceCount;\r
31 LIST_ENTRY* Entry;\r
32 UINTN SupportedDeviceSelected;\r
33 UINTN Index;\r
34\r
35 //\r
36 // List the Boot Devices supported\r
37 //\r
38\r
39 // Start all the drivers first\r
40 BdsConnectAllDrivers ();\r
41\r
42 // List the supported devices\r
43 Status = BootDeviceListSupportedInit (&SupportedDeviceList);\r
44 ASSERT_EFI_ERROR(Status);\r
45\r
46 SupportedDeviceCount = 0;\r
47 for (Entry = GetFirstNode (&SupportedDeviceList);\r
48 !IsNull (&SupportedDeviceList,Entry);\r
49 Entry = GetNextNode (&SupportedDeviceList,Entry)\r
50 )\r
51 {\r
52 *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
53 Print(L"[%d] %s\n",SupportedDeviceCount+1,(*SupportedBootDevice)->Description);\r
54\r
55 DEBUG_CODE_BEGIN();\r
56 CHAR16* DevicePathTxt;\r
57 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
58\r
59 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
60 ASSERT_EFI_ERROR(Status);\r
61 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ((*SupportedBootDevice)->DevicePathProtocol,TRUE,TRUE);\r
62\r
63 Print(L"\t- %s\n",DevicePathTxt);\r
64\r
65 FreePool(DevicePathTxt);\r
66 DEBUG_CODE_END();\r
67\r
68 SupportedDeviceCount++;\r
69 }\r
70\r
71 if (SupportedDeviceCount == 0) {\r
72 Print(L"There is no supported device.\n");\r
73 Status = EFI_ABORTED;\r
74 goto EXIT;\r
75 }\r
76\r
77 //\r
78 // Select the Boot Device\r
79 //\r
80 SupportedDeviceSelected = 0;\r
81 while (SupportedDeviceSelected == 0) {\r
82 Print(L"Select the Boot Device: ");\r
83 Status = GetHIInputInteger (&SupportedDeviceSelected);\r
84 if (EFI_ERROR(Status)) {\r
85 Status = EFI_ABORTED;\r
86 goto EXIT;\r
87 } else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) {\r
88 Print(L"Invalid input (max %d)\n",SupportedDeviceCount);\r
89 SupportedDeviceSelected = 0;\r
90 }\r
91 }\r
92\r
93 //\r
94 // Get the Device Path for the selected boot device\r
95 //\r
96 Index = 1;\r
97 for (Entry = GetFirstNode (&SupportedDeviceList);\r
98 !IsNull (&SupportedDeviceList,Entry);\r
99 Entry = GetNextNode (&SupportedDeviceList,Entry)\r
100 )\r
101 {\r
102 if (Index == SupportedDeviceSelected) {\r
103 *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
104 break;\r
105 }\r
106 Index++;\r
107 }\r
108\r
109EXIT:\r
110 BootDeviceListSupportedFree (&SupportedDeviceList, *SupportedBootDevice);\r
111 return Status;\r
112}\r
113\r
114EFI_STATUS\r
115BootMenuAddBootOption (\r
116 IN LIST_ENTRY *BootOptionsList\r
117 )\r
118{\r
119 EFI_STATUS Status;\r
120 BDS_SUPPORTED_DEVICE* SupportedBootDevice;\r
121 ARM_BDS_LOADER_ARGUMENTS* BootArguments;\r
122 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
123 CHAR8 AsciiCmdLine[BOOT_DEVICE_OPTION_MAX];\r
124 CHAR16 CmdLine[BOOT_DEVICE_OPTION_MAX];\r
125 UINT32 Attributes;\r
126 ARM_BDS_LOADER_TYPE BootType;\r
127 BDS_LOAD_OPTION_ENTRY *BdsLoadOptionEntry;\r
128 EFI_DEVICE_PATH *DevicePath;\r
129 EFI_DEVICE_PATH_PROTOCOL *DevicePathNodes;\r
130 EFI_DEVICE_PATH_PROTOCOL *InitrdPathNodes;\r
131 EFI_DEVICE_PATH_PROTOCOL *InitrdPath;\r
132 UINTN CmdLineSize;\r
133 BOOLEAN InitrdSupport;\r
134 UINTN InitrdSize;\r
135 UINT8* OptionalData;\r
136 UINTN OptionalDataSize;\r
137\r
138 Attributes = 0;\r
139 SupportedBootDevice = NULL;\r
140\r
141 // List the Boot Devices supported\r
142 Status = SelectBootDevice (&SupportedBootDevice);\r
143 if (EFI_ERROR(Status)) {\r
144 Status = EFI_ABORTED;\r
145 goto EXIT;\r
146 }\r
147\r
148 // Create the specific device path node\r
149 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application or the kernel", &DevicePathNodes);\r
150 if (EFI_ERROR(Status)) {\r
151 Status = EFI_ABORTED;\r
152 goto EXIT;\r
153 }\r
154 // Append the Device Path to the selected device path\r
155 DevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNodes);\r
156 if (DevicePath == NULL) {\r
157 Status = EFI_OUT_OF_RESOURCES;\r
158 goto EXIT;\r
159 }\r
160\r
161 if (SupportedBootDevice->Support->RequestBootType) {\r
162 Status = BootDeviceGetType (DevicePath, &BootType, &Attributes);\r
163 if (EFI_ERROR(Status)) {\r
164 Status = EFI_ABORTED;\r
165 goto EXIT;\r
166 }\r
167 } else {\r
168 BootType = BDS_LOADER_EFI_APPLICATION;\r
169 }\r
170\r
171 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
172 Print(L"Add an initrd: ");\r
173 Status = GetHIInputBoolean (&InitrdSupport);\r
174 if (EFI_ERROR(Status)) {\r
175 Status = EFI_ABORTED;\r
176 goto EXIT;\r
177 }\r
178\r
179 if (InitrdSupport) {\r
180 // Create the specific device path node\r
181 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"initrd", &InitrdPathNodes);\r
182 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
183 Status = EFI_ABORTED;\r
184 goto EXIT;\r
185 }\r
186\r
187 if (InitrdPathNodes != NULL) {\r
188 // Append the Device Path to the selected device path\r
189 InitrdPath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes);\r
190 if (InitrdPath == NULL) {\r
191 Status = EFI_OUT_OF_RESOURCES;\r
192 goto EXIT;\r
193 }\r
194 } else {\r
195 InitrdPath = NULL;\r
196 }\r
197 } else {\r
198 InitrdPath = NULL;\r
199 }\r
200\r
201 Print(L"Arguments to pass to the binary: ");\r
202 Status = GetHIInputAscii (AsciiCmdLine, BOOT_DEVICE_OPTION_MAX);\r
203 if (EFI_ERROR(Status)) {\r
204 Status = EFI_ABORTED;\r
205 goto FREE_DEVICE_PATH;\r
206 }\r
207\r
208 CmdLineSize = AsciiStrSize (AsciiCmdLine);\r
209 InitrdSize = GetDevicePathSize (InitrdPath);\r
210\r
211 OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize;\r
212 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize);\r
213\r
214 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;\r
215 BootArguments->LinuxArguments.InitrdSize = InitrdSize;\r
216 CopyMem ((VOID*)(&BootArguments->LinuxArguments + 1), AsciiCmdLine, CmdLineSize);\r
217 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);\r
218\r
219 OptionalData = (UINT8*)BootArguments;\r
220 } else {\r
221 Print (L"Arguments to pass to the EFI Application: ");\r
222 Status = GetHIInputStr (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
223 if (EFI_ERROR (Status)) {\r
224 Status = EFI_ABORTED;\r
225 goto EXIT;\r
226 }\r
227\r
228 OptionalData = (UINT8*)CmdLine;\r
229 OptionalDataSize = StrSize (CmdLine);\r
230 }\r
231\r
232 Print(L"Description for this new Entry: ");\r
233 Status = GetHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
234 if (EFI_ERROR(Status)) {\r
235 Status = EFI_ABORTED;\r
236 goto FREE_DEVICE_PATH;\r
237 }\r
238\r
239 // Create new entry\r
240 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY));\r
241 Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize, &BdsLoadOptionEntry->BdsLoadOption);\r
242 if (!EFI_ERROR(Status)) {\r
243 InsertTailList (BootOptionsList, &BdsLoadOptionEntry->Link);\r
244 }\r
245\r
246FREE_DEVICE_PATH:\r
247 FreePool (DevicePath);\r
248\r
249EXIT:\r
250 if (Status == EFI_ABORTED) {\r
251 Print(L"\n");\r
252 }\r
253 FreePool(SupportedBootDevice);\r
254 return Status;\r
255}\r
256\r
257STATIC\r
258EFI_STATUS\r
259BootMenuSelectBootOption (\r
260 IN LIST_ENTRY* BootOptionsList,\r
261 IN CONST CHAR16* InputStatement,\r
262 OUT BDS_LOAD_OPTION_ENTRY** BdsLoadOptionEntry\r
263 )\r
264{\r
265 EFI_STATUS Status;\r
266 LIST_ENTRY* Entry;\r
267 BDS_LOAD_OPTION* BdsLoadOption;\r
268 UINTN BootOptionSelected;\r
269 UINTN BootOptionCount;\r
270 UINTN Index;\r
271 BOOLEAN IsUnicode;\r
272\r
273 // Display the list of supported boot devices\r
274 BootOptionCount = 0;\r
275 for (Entry = GetFirstNode (BootOptionsList);\r
276 !IsNull (BootOptionsList,Entry);\r
277 Entry = GetNextNode (BootOptionsList, Entry)\r
278 )\r
279 {\r
280 BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);\r
281\r
282 Print (L"[%d] %s\n", (BootOptionCount + 1), BdsLoadOption->Description);\r
283\r
284 DEBUG_CODE_BEGIN();\r
285 CHAR16* DevicePathTxt;\r
286 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
287 ARM_BDS_LOADER_TYPE LoaderType;\r
288 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;\r
289\r
290 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
291 ASSERT_EFI_ERROR(Status);\r
292 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BdsLoadOption->FilePathList,TRUE,TRUE);\r
293\r
294 Print(L"\t- %s\n",DevicePathTxt);\r
295 OptionalData = BdsLoadOption->OptionalData;\r
296 if (IS_ARM_BDS_BOOTENTRY (BdsLoadOption)) {\r
297 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);\r
298 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
299 Print (L"\t- Arguments: %a\n",&OptionalData->Arguments.LinuxArguments + 1);\r
300 }\r
301 } else if (OptionalData != NULL) {\r
302 if (IsPrintableString (OptionalData, &IsUnicode)) {\r
303 if (IsUnicode) {\r
304 Print (L"\t- Arguments: %s\n", OptionalData);\r
305 } else {\r
306 AsciiPrint ("\t- Arguments: %a\n", OptionalData);\r
307 }\r
308 }\r
309 }\r
310\r
311 FreePool(DevicePathTxt);\r
312 DEBUG_CODE_END();\r
313\r
314 BootOptionCount++;\r
315 }\r
316\r
317 // Check if a valid boot option(s) is found\r
318 if (BootOptionCount == 0) {\r
319 if (StrCmp (InputStatement, DELETE_BOOT_ENTRY) == 0) {\r
320 Print (L"Nothing to remove!\n");\r
321 } else if (StrCmp (InputStatement, UPDATE_BOOT_ENTRY) == 0) {\r
322 Print (L"Couldn't find valid boot entries\n");\r
323 } else{\r
324 Print (L"No supported Boot Entry.\n");\r
325 }\r
326\r
327 return EFI_NOT_FOUND;\r
328 }\r
329\r
330 // Get the index of the boot device to delete\r
331 BootOptionSelected = 0;\r
332 while (BootOptionSelected == 0) {\r
333 Print(InputStatement);\r
334 Status = GetHIInputInteger (&BootOptionSelected);\r
335 if (EFI_ERROR(Status)) {\r
336 return Status;\r
337 } else if ((BootOptionSelected == 0) || (BootOptionSelected > BootOptionCount)) {\r
338 Print(L"Invalid input (max %d)\n",BootOptionCount);\r
339 BootOptionSelected = 0;\r
340 }\r
341 }\r
342\r
343 // Get the structure of the Boot device to delete\r
344 Index = 1;\r
345 for (Entry = GetFirstNode (BootOptionsList);\r
346 !IsNull (BootOptionsList, Entry);\r
347 Entry = GetNextNode (BootOptionsList,Entry)\r
348 )\r
349 {\r
350 if (Index == BootOptionSelected) {\r
351 *BdsLoadOptionEntry = LOAD_OPTION_ENTRY_FROM_LINK(Entry);\r
352 break;\r
353 }\r
354 Index++;\r
355 }\r
356\r
357 return EFI_SUCCESS;\r
358}\r
359\r
360EFI_STATUS\r
361BootMenuRemoveBootOption (\r
362 IN LIST_ENTRY *BootOptionsList\r
363 )\r
364{\r
365 EFI_STATUS Status;\r
366 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;\r
367\r
368 Status = BootMenuSelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, &BootOptionEntry);\r
369 if (EFI_ERROR(Status)) {\r
370 return Status;\r
371 }\r
372\r
373 // If the Boot Option was attached to a list remove it\r
374 if (!IsListEmpty (&BootOptionEntry->Link)) {\r
375 // Remove the entry from the list\r
376 RemoveEntryList (&BootOptionEntry->Link);\r
377 }\r
378\r
379 // Delete the BDS Load option structures\r
380 BootOptionDelete (BootOptionEntry->BdsLoadOption);\r
381\r
382 return EFI_SUCCESS;\r
383}\r
384\r
385EFI_STATUS\r
386BootMenuUpdateBootOption (\r
387 IN LIST_ENTRY *BootOptionsList\r
388 )\r
389{\r
390 EFI_STATUS Status;\r
391 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;\r
392 BDS_LOAD_OPTION *BootOption;\r
393 BDS_LOAD_OPTION_SUPPORT* DeviceSupport;\r
394 ARM_BDS_LOADER_ARGUMENTS* BootArguments;\r
395 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
396 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];\r
397 CHAR16 UnicodeCmdLine[BOOT_DEVICE_OPTION_MAX];\r
398 EFI_DEVICE_PATH *DevicePath;\r
399 EFI_DEVICE_PATH *TempInitrdPath;\r
400 ARM_BDS_LOADER_TYPE BootType;\r
401 ARM_BDS_LOADER_OPTIONAL_DATA* LoaderOptionalData;\r
402 ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;\r
403 EFI_DEVICE_PATH *InitrdPathNodes;\r
404 EFI_DEVICE_PATH *InitrdPath;\r
405 UINTN InitrdSize;\r
406 UINTN CmdLineSize;\r
407 BOOLEAN InitrdSupport;\r
408 UINT8* OptionalData;\r
409 UINTN OptionalDataSize;\r
410 BOOLEAN IsPrintable;\r
411 BOOLEAN IsUnicode;\r
412\r
413 Status = BootMenuSelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry);\r
414 if (EFI_ERROR(Status)) {\r
415 return Status;\r
416 }\r
417 BootOption = BootOptionEntry->BdsLoadOption;\r
418\r
419 // Get the device support for this Boot Option\r
420 Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport);\r
421 if (EFI_ERROR(Status)) {\r
422 Print(L"Not possible to retrieve the supported device for the update\n");\r
423 return EFI_UNSUPPORTED;\r
424 }\r
425\r
426 Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath);\r
427 if (EFI_ERROR(Status)) {\r
428 Status = EFI_ABORTED;\r
429 goto EXIT;\r
430 }\r
431\r
432 if (DeviceSupport->RequestBootType) {\r
433 Status = BootDeviceGetType (DevicePath, &BootType, &BootOption->Attributes);\r
434 if (EFI_ERROR(Status)) {\r
435 Status = EFI_ABORTED;\r
436 goto EXIT;\r
437 }\r
438 }\r
439\r
440 LoaderOptionalData = BootOption->OptionalData;\r
441 if (LoaderOptionalData != NULL) {\r
442 BootType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((UINT32 *)(&LoaderOptionalData->Header.LoaderType));\r
443 } else {\r
444 BootType = BDS_LOADER_EFI_APPLICATION;\r
445 }\r
446\r
447 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
448 LinuxArguments = &LoaderOptionalData->Arguments.LinuxArguments;\r
449\r
450 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);\r
451\r
452 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);\r
453 if (InitrdSize > 0) {\r
454 Print(L"Keep the initrd: ");\r
455 } else {\r
456 Print(L"Add an initrd: ");\r
457 }\r
458 Status = GetHIInputBoolean (&InitrdSupport);\r
459 if (EFI_ERROR(Status)) {\r
460 Status = EFI_ABORTED;\r
461 goto EXIT;\r
462 }\r
463\r
464 if (InitrdSupport) {\r
465 if (InitrdSize > 0) {\r
466 // Case we update the initrd device path\r
467 Status = DeviceSupport->UpdateDevicePathNode ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize), L"initrd", &InitrdPath);\r
468 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
469 Status = EFI_ABORTED;\r
470 goto EXIT;\r
471 }\r
472 InitrdSize = GetDevicePathSize (InitrdPath);\r
473 } else {\r
474 // Case we create the initrd device path\r
475\r
476 Status = DeviceSupport->CreateDevicePathNode (L"initrd", &InitrdPathNodes);\r
477 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
478 Status = EFI_ABORTED;\r
479 goto EXIT;\r
480 }\r
481\r
482 if (InitrdPathNodes != NULL) {\r
483 // Duplicate Linux kernel Device Path\r
484 TempInitrdPath = DuplicateDevicePath (BootOption->FilePathList);\r
485 // Replace Linux kernel Node by EndNode\r
486 SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath));\r
487 // Append the Device Path to the selected device path\r
488 InitrdPath = AppendDevicePath (TempInitrdPath, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes);\r
489 FreePool (TempInitrdPath);\r
490 if (InitrdPath == NULL) {\r
491 Status = EFI_OUT_OF_RESOURCES;\r
492 goto EXIT;\r
493 }\r
494 InitrdSize = GetDevicePathSize (InitrdPath);\r
495 } else {\r
496 InitrdPath = NULL;\r
497 }\r
498 }\r
499 } else {\r
500 InitrdSize = 0;\r
501 }\r
502\r
503 Print(L"Arguments to pass to the binary: ");\r
504 if (CmdLineSize > 0) {\r
505 AsciiStrnCpy(CmdLine, (CONST CHAR8*)(LinuxArguments + 1), CmdLineSize);\r
506 } else {\r
507 CmdLine[0] = '\0';\r
508 }\r
509 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
510 if (EFI_ERROR(Status)) {\r
511 Status = EFI_ABORTED;\r
512 goto FREE_DEVICE_PATH;\r
513 }\r
514\r
515 CmdLineSize = AsciiStrSize (CmdLine);\r
516\r
517 OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize;\r
518 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize);\r
519 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;\r
520 BootArguments->LinuxArguments.InitrdSize = InitrdSize;\r
521 CopyMem (&BootArguments->LinuxArguments + 1, CmdLine, CmdLineSize);\r
522 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);\r
523\r
524 OptionalData = (UINT8*)BootArguments;\r
525 } else {\r
526 Print (L"Arguments to pass to the EFI Application: ");\r
527\r
528 if (BootOption->OptionalDataSize > 0) {\r
529 IsPrintable = IsPrintableString (BootOption->OptionalData, &IsUnicode);\r
530 if (IsPrintable) {\r
531 if (IsUnicode) {\r
532 StrnCpy (UnicodeCmdLine, BootOption->OptionalData, BootOption->OptionalDataSize / 2);\r
533 } else {\r
534 AsciiStrnCpy (CmdLine, BootOption->OptionalData, BootOption->OptionalDataSize);\r
535 }\r
536 }\r
537 } else {\r
538 UnicodeCmdLine[0] = L'\0';\r
539 IsPrintable = TRUE;\r
540 IsUnicode = TRUE;\r
541 }\r
542\r
543 // We do not request arguments for OptionalData that cannot be printed\r
544 if (IsPrintable) {\r
545 if (IsUnicode) {\r
546 Status = EditHIInputStr (UnicodeCmdLine, BOOT_DEVICE_OPTION_MAX);\r
547 if (EFI_ERROR (Status)) {\r
548 Status = EFI_ABORTED;\r
549 goto FREE_DEVICE_PATH;\r
550 }\r
551\r
552 OptionalData = (UINT8*)UnicodeCmdLine;\r
553 OptionalDataSize = StrSize (UnicodeCmdLine);\r
554 } else {\r
555 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
556 if (EFI_ERROR (Status)) {\r
557 Status = EFI_ABORTED;\r
558 goto FREE_DEVICE_PATH;\r
559 }\r
560\r
561 OptionalData = (UINT8*)CmdLine;\r
562 OptionalDataSize = AsciiStrSize (CmdLine);\r
563 }\r
564 } else {\r
565 // We keep the former OptionalData\r
566 OptionalData = BootOption->OptionalData;\r
567 OptionalDataSize = BootOption->OptionalDataSize;\r
568 }\r
569 }\r
570\r
571 Print(L"Description for this new Entry: ");\r
572 StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX);\r
573 Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
574 if (EFI_ERROR(Status)) {\r
575 Status = EFI_ABORTED;\r
576 goto FREE_DEVICE_PATH;\r
577 }\r
578\r
579 // Update the entry\r
580 Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize);\r
581\r
582FREE_DEVICE_PATH:\r
583 FreePool (DevicePath);\r
584\r
585EXIT:\r
586 if (Status == EFI_ABORTED) {\r
587 Print(L"\n");\r
588 }\r
589 return Status;\r
590}\r
591\r
592EFI_STATUS\r
593UpdateFdtPath (\r
594 IN LIST_ENTRY *BootOptionsList\r
595 )\r
596{\r
597 EFI_STATUS Status;\r
598 UINTN FdtDevicePathSize;\r
599 BDS_SUPPORTED_DEVICE *SupportedBootDevice;\r
600 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePathNodes;\r
601 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePath;\r
602\r
603 Status = SelectBootDevice (&SupportedBootDevice);\r
604 if (EFI_ERROR(Status)) {\r
605 Status = EFI_ABORTED;\r
606 goto EXIT;\r
607 }\r
608\r
609 // Create the specific device path node\r
610 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNodes);\r
611 if (EFI_ERROR(Status)) {\r
612 Status = EFI_ABORTED;\r
613 goto EXIT;\r
614 }\r
615\r
616 if (FdtDevicePathNodes != NULL) {\r
617 // Append the Device Path node to the select device path\r
618 FdtDevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNodes);\r
619 FdtDevicePathSize = GetDevicePathSize (FdtDevicePath);\r
620 Status = gRT->SetVariable (\r
621 (CHAR16*)L"Fdt",\r
622 &gArmGlobalVariableGuid,\r
623 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
624 FdtDevicePathSize,\r
625 FdtDevicePath\r
626 );\r
627 ASSERT_EFI_ERROR(Status);\r
628 } else {\r
629 gRT->SetVariable (\r
630 (CHAR16*)L"Fdt",\r
631 &gArmGlobalVariableGuid,\r
632 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
633 0,\r
634 NULL\r
635 );\r
636 ASSERT_EFI_ERROR(Status);\r
637 }\r
638\r
639EXIT:\r
640 if (Status == EFI_ABORTED) {\r
641 Print(L"\n");\r
642 }\r
643 FreePool(SupportedBootDevice);\r
644 return Status;\r
645}\r
646\r
647/**\r
648 Set boot timeout\r
649\r
650 Ask for the boot timeout in seconds and if the input succeeds assign the\r
651 input value to the UEFI global variable "Timeout". This function is called\r
652 when the user selects the "Set Boot Timeout" of the boot manager menu.\r
653\r
654 @param[in] BootOptionsList List of the boot devices, not used here\r
655\r
656 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard\r
657 input and assigned to the UEFI "Timeout" global\r
658 variable\r
659 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global\r
660 variable "Timeout" has failed.\r
661**/\r
662EFI_STATUS\r
663STATIC\r
664BootMenuSetBootTimeout (\r
665 IN LIST_ENTRY *BootOptionsList\r
666 )\r
667{\r
668 EFI_STATUS Status;\r
669 UINTN Input;\r
670 UINT16 Timeout;\r
671\r
672 Print (L"Timeout duration (in seconds): ");\r
673 Status = GetHIInputInteger (&Input);\r
674 if (EFI_ERROR (Status)) {\r
675 Print (L"\n");\r
676 goto ErrorExit;\r
677 }\r
678\r
679 Timeout = Input;\r
680 Status = gRT->SetVariable (\r
681 (CHAR16*)L"Timeout",\r
682 &gEfiGlobalVariableGuid,\r
683 EFI_VARIABLE_NON_VOLATILE |\r
684 EFI_VARIABLE_BOOTSERVICE_ACCESS |\r
685 EFI_VARIABLE_RUNTIME_ACCESS,\r
686 sizeof (UINT16),\r
687 &Timeout\r
688 );\r
689 ASSERT_EFI_ERROR (Status);\r
690\r
691ErrorExit:\r
692 return Status;\r
693}\r
694\r
695struct BOOT_MANAGER_ENTRY {\r
696 CONST CHAR16* Description;\r
697 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
698} BootManagerEntries[] = {\r
699 { L"Add Boot Device Entry", BootMenuAddBootOption },\r
700 { L"Update Boot Device Entry", BootMenuUpdateBootOption },\r
701 { L"Remove Boot Device Entry", BootMenuRemoveBootOption },\r
702 { L"Update FDT path", UpdateFdtPath },\r
703 { L"Set Boot Timeout", BootMenuSetBootTimeout },\r
704};\r
705\r
706EFI_STATUS\r
707BootMenuManager (\r
708 IN LIST_ENTRY *BootOptionsList\r
709 )\r
710{\r
711 UINTN Index;\r
712 UINTN OptionSelected;\r
713 UINTN BootManagerEntryCount;\r
714 EFI_STATUS Status;\r
715\r
716 BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);\r
717\r
718 while (TRUE) {\r
719 // Display Boot Manager menu\r
720 for (Index = 0; Index < BootManagerEntryCount; Index++) {\r
721 Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);\r
722 }\r
723 Print(L"[%d] Return to main menu\n",Index+1);\r
724\r
725 // Select which entry to call\r
726 Print(L"Choice: ");\r
727 Status = GetHIInputInteger (&OptionSelected);\r
728 if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {\r
729 if (EFI_ERROR(Status)) {\r
730 Print(L"\n");\r
731 }\r
732 return EFI_SUCCESS;\r
733 } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {\r
734 BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);\r
735 }\r
736 }\r
737 // Should never go here\r
738}\r
739\r
740EFI_STATUS\r
741BootShell (\r
742 IN LIST_ENTRY *BootOptionsList\r
743 )\r
744{\r
745 EFI_STATUS Status;\r
746\r
747 // Start EFI Shell\r
748 Status = BdsLoadApplication (mImageHandle, L"Shell", 0, NULL);\r
749 if (Status == EFI_NOT_FOUND) {\r
750 Print (L"Error: EFI Application not found.\n");\r
751 } else if (EFI_ERROR(Status)) {\r
752 Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);\r
753 }\r
754\r
755 return Status;\r
756}\r
757\r
758struct BOOT_MAIN_ENTRY {\r
759 CONST CHAR16* Description;\r
760 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
761} BootMainEntries[] = {\r
762 { L"Shell", BootShell },\r
763 { L"Boot Manager", BootMenuManager },\r
764};\r
765\r
766\r
767EFI_STATUS\r
768BootMenuMain (\r
769 VOID\r
770 )\r
771{\r
772 LIST_ENTRY BootOptionsList;\r
773 UINTN OptionCount;\r
774 UINTN BootOptionCount;\r
775 EFI_STATUS Status;\r
776 LIST_ENTRY* Entry;\r
777 BDS_LOAD_OPTION* BootOption;\r
778 UINTN BootOptionSelected;\r
779 UINTN Index;\r
780 UINTN BootMainEntryCount;\r
781 BOOLEAN IsUnicode;\r
782\r
783 BootOption = NULL;\r
784 BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);\r
785\r
786 while (TRUE) {\r
787 // Get Boot#### list\r
788 BootOptionList (&BootOptionsList);\r
789\r
790 OptionCount = 1;\r
791\r
792 // Display the Boot options\r
793 for (Entry = GetFirstNode (&BootOptionsList);\r
794 !IsNull (&BootOptionsList,Entry);\r
795 Entry = GetNextNode (&BootOptionsList,Entry)\r
796 )\r
797 {\r
798 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
799\r
800 Print(L"[%d] %s\n", OptionCount, BootOption->Description);\r
801\r
802 DEBUG_CODE_BEGIN();\r
803 CHAR16* DevicePathTxt;\r
804 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
805 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;\r
806 UINTN CmdLineSize;\r
807 ARM_BDS_LOADER_TYPE LoaderType;\r
808\r
809 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
810 if (EFI_ERROR(Status)) {\r
811 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)\r
812 DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));\r
813 return Status;\r
814 }\r
815 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE);\r
816\r
817 Print(L"\t- %s\n",DevicePathTxt);\r
818\r
819 // If it is a supported BootEntry then print its details\r
820 if (IS_ARM_BDS_BOOTENTRY (BootOption)) {\r
821 OptionalData = BootOption->OptionalData;\r
822 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);\r
823 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
824 if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.InitrdSize) > 0) {\r
825 CmdLineSize = ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize);\r
826 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (\r
827 GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(&OptionalData->Arguments.LinuxArguments + 1) + CmdLineSize)), TRUE, TRUE);\r
828 Print(L"\t- Initrd: %s\n", DevicePathTxt);\r
829 }\r
830 if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize) > 0) {\r
831 Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1));\r
832 }\r
833 }\r
834\r
835 switch (LoaderType) {\r
836 case BDS_LOADER_EFI_APPLICATION:\r
837 Print(L"\t- LoaderType: EFI Application\n");\r
838 break;\r
839\r
840 case BDS_LOADER_KERNEL_LINUX_ATAG:\r
841 Print(L"\t- LoaderType: Linux kernel with ATAG support\n");\r
842 break;\r
843\r
844 case BDS_LOADER_KERNEL_LINUX_FDT:\r
845 Print(L"\t- LoaderType: Linux kernel with FDT support\n");\r
846 break;\r
847\r
848 default:\r
849 Print(L"\t- LoaderType: Not recognized (%d)\n", LoaderType);\r
850 }\r
851 } else if (BootOption->OptionalData != NULL) {\r
852 if (IsPrintableString (BootOption->OptionalData, &IsUnicode)) {\r
853 if (IsUnicode) {\r
854 Print (L"\t- Arguments: %s\n", BootOption->OptionalData);\r
855 } else {\r
856 AsciiPrint ("\t- Arguments: %a\n", BootOption->OptionalData);\r
857 }\r
858 }\r
859 }\r
860 FreePool(DevicePathTxt);\r
861 DEBUG_CODE_END();\r
862\r
863 OptionCount++;\r
864 }\r
865 BootOptionCount = OptionCount-1;\r
866\r
867 // Display the hardcoded Boot entries\r
868 for (Index = 0; Index < BootMainEntryCount; Index++) {\r
869 Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);\r
870 OptionCount++;\r
871 }\r
872\r
873 // Request the boot entry from the user\r
874 BootOptionSelected = 0;\r
875 while (BootOptionSelected == 0) {\r
876 Print(L"Start: ");\r
877 Status = GetHIInputInteger (&BootOptionSelected);\r
878 if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {\r
879 Print(L"Invalid input (max %d)\n",(OptionCount-1));\r
880 BootOptionSelected = 0;\r
881 }\r
882 }\r
883\r
884 // Start the selected entry\r
885 if (BootOptionSelected > BootOptionCount) {\r
886 // Start the hardcoded entry\r
887 Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);\r
888 } else {\r
889 // Find the selected entry from the Boot#### list\r
890 Index = 1;\r
891 for (Entry = GetFirstNode (&BootOptionsList);\r
892 !IsNull (&BootOptionsList,Entry);\r
893 Entry = GetNextNode (&BootOptionsList,Entry)\r
894 )\r
895 {\r
896 if (Index == BootOptionSelected) {\r
897 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
898 break;\r
899 }\r
900 Index++;\r
901 }\r
902\r
903 Status = BootOptionStart (BootOption);\r
904 }\r
905 }\r
906 // Should never go here\r
907}\r