]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Bds/BootMenu.c
ArmPkg/BdsLib: Free the memory when Linux fails to start
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootMenu.c
CommitLineData
ea46ebbe 1/** @file\r
2*\r
aeaf64d6 3* Copyright (c) 2011-2013, ARM Limited. All rights reserved.\r
ea46ebbe 4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "BdsInternal.h"\r
16\r
aeaf64d6 17#include <Guid/ArmGlobalVariableHob.h>\r
18\r
ea46ebbe 19extern EFI_HANDLE mImageHandle;\r
20extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;\r
21\r
aeaf64d6 22\r
ea46ebbe 23EFI_STATUS\r
656416bc 24SelectBootDevice (\r
25 OUT BDS_SUPPORTED_DEVICE** SupportedBootDevice\r
ea46ebbe 26 )\r
27{\r
656416bc 28 EFI_STATUS Status;\r
ea46ebbe 29 LIST_ENTRY SupportedDeviceList;\r
30 UINTN SupportedDeviceCount;\r
ea46ebbe 31 LIST_ENTRY* Entry;\r
32 UINTN SupportedDeviceSelected;\r
ea46ebbe 33 UINTN Index;\r
ea46ebbe 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
656416bc 52 *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
53 Print(L"[%d] %s\n",SupportedDeviceCount+1,(*SupportedBootDevice)->Description);\r
ea46ebbe 54\r
55 DEBUG_CODE_BEGIN();\r
56 CHAR16* DevicePathTxt;\r
57 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
58\r
ff7666c5 59 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
ea46ebbe 60 ASSERT_EFI_ERROR(Status);\r
ff7666c5 61 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ((*SupportedBootDevice)->DevicePathProtocol,TRUE,TRUE);\r
ea46ebbe 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
ff7666c5 88 Print(L"Invalid input (max %d)\n",SupportedDeviceCount);\r
ea46ebbe 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
656416bc 103 *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
ea46ebbe 104 break;\r
105 }\r
106 Index++;\r
107 }\r
aeaf64d6 108\r
656416bc 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
2ccfb71e 119 EFI_STATUS Status;\r
120 BDS_SUPPORTED_DEVICE* SupportedBootDevice;\r
121 ARM_BDS_LOADER_ARGUMENTS* BootArguments;\r
74b96132 122 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
2ccfb71e 123 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];\r
124 UINT32 Attributes;\r
125 ARM_BDS_LOADER_TYPE BootType;\r
a6e97d28 126 BDS_LOAD_OPTION_ENTRY *BdsLoadOptionEntry;\r
2ccfb71e 127 EFI_DEVICE_PATH *DevicePath;\r
128 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
129 EFI_DEVICE_PATH_PROTOCOL *InitrdPathNode;\r
130 EFI_DEVICE_PATH_PROTOCOL *InitrdPath;\r
131 UINTN CmdLineSize;\r
22a262c8 132 BOOLEAN InitrdSupport;\r
2ccfb71e 133 UINTN InitrdSize;\r
656416bc 134\r
135 Attributes = 0;\r
136 SupportedBootDevice = NULL;\r
137\r
138 // List the Boot Devices supported\r
2ccfb71e 139 Status = SelectBootDevice (&SupportedBootDevice);\r
656416bc 140 if (EFI_ERROR(Status)) {\r
141 Status = EFI_ABORTED;\r
142 goto EXIT;\r
143 }\r
ea46ebbe 144\r
145 // Create the specific device path node\r
22a262c8 146 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application or the kernel", &DevicePathNode, &BootType, &Attributes);\r
ea46ebbe 147 if (EFI_ERROR(Status)) {\r
148 Status = EFI_ABORTED;\r
149 goto EXIT;\r
150 }\r
151 // Append the Device Path node to the select device path\r
152 DevicePath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNode);\r
153\r
2ccfb71e 154 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
22a262c8 155 Print(L"Add an initrd: ");\r
156 Status = GetHIInputBoolean (&InitrdSupport);\r
157 if (EFI_ERROR(Status)) {\r
656416bc 158 Status = EFI_ABORTED;\r
159 goto EXIT;\r
160 }\r
161\r
22a262c8 162 if (InitrdSupport) {\r
163 // Create the specific device path node\r
164 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"initrd", &InitrdPathNode, NULL, NULL);\r
165 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
166 Status = EFI_ABORTED;\r
167 goto EXIT;\r
168 }\r
169\r
170 if (InitrdPathNode != NULL) {\r
171 // Append the Device Path node to the select device path\r
172 InitrdPath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNode);\r
173 } else {\r
174 InitrdPath = NULL;\r
175 }\r
656416bc 176 } else {\r
2ccfb71e 177 InitrdPath = NULL;\r
656416bc 178 }\r
179\r
180 Print(L"Arguments to pass to the binary: ");\r
2ccfb71e 181 Status = GetHIInputAscii (CmdLine,BOOT_DEVICE_OPTION_MAX);\r
656416bc 182 if (EFI_ERROR(Status)) {\r
183 Status = EFI_ABORTED;\r
184 goto FREE_DEVICE_PATH;\r
185 }\r
2ccfb71e 186\r
187 CmdLineSize = AsciiStrSize (CmdLine);\r
188 InitrdSize = GetDevicePathSize (InitrdPath);\r
189\r
190 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize);\r
aeaf64d6 191\r
2ccfb71e 192 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;\r
193 BootArguments->LinuxArguments.InitrdSize = InitrdSize;\r
194 CopyMem ((VOID*)(&BootArguments->LinuxArguments + 1), CmdLine, CmdLineSize);\r
195 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);\r
196 } else {\r
197 BootArguments = NULL;\r
ea46ebbe 198 }\r
199\r
200 Print(L"Description for this new Entry: ");\r
74b96132 201 Status = GetHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
ea46ebbe 202 if (EFI_ERROR(Status)) {\r
203 Status = EFI_ABORTED;\r
204 goto FREE_DEVICE_PATH;\r
205 }\r
206\r
ea46ebbe 207 // Create new entry\r
a6e97d28 208 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY));\r
209 Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, BootArguments, &BdsLoadOptionEntry->BdsLoadOption);\r
ea46ebbe 210 if (!EFI_ERROR(Status)) {\r
a6e97d28 211 InsertTailList (BootOptionsList, &BdsLoadOptionEntry->Link);\r
ea46ebbe 212 }\r
213\r
ea46ebbe 214FREE_DEVICE_PATH:\r
215 FreePool (DevicePath);\r
216\r
aeaf64d6 217\r
ea46ebbe 218EXIT:\r
656416bc 219 if (Status == EFI_ABORTED) {\r
220 Print(L"\n");\r
221 }\r
222 FreePool(SupportedBootDevice);\r
ea46ebbe 223 return Status;\r
224}\r
225\r
226STATIC\r
227EFI_STATUS\r
228BootMenuSelectBootOption (\r
a6e97d28 229 IN LIST_ENTRY* BootOptionsList,\r
230 IN CONST CHAR16* InputStatement,\r
231 IN BOOLEAN OnlyArmBdsBootEntry,\r
232 OUT BDS_LOAD_OPTION_ENTRY** BdsLoadOptionEntry\r
ea46ebbe 233 )\r
234{\r
a6e97d28 235 EFI_STATUS Status;\r
236 LIST_ENTRY* Entry;\r
237 BDS_LOAD_OPTION* BdsLoadOption;\r
238 UINTN BootOptionSelected;\r
239 UINTN BootOptionCount;\r
240 UINTN Index;\r
ea46ebbe 241\r
242 // Display the list of supported boot devices\r
c93ab96c 243 BootOptionCount = 0;\r
ea46ebbe 244 for (Entry = GetFirstNode (BootOptionsList);\r
245 !IsNull (BootOptionsList,Entry);\r
a6e97d28 246 Entry = GetNextNode (BootOptionsList, Entry)\r
ea46ebbe 247 )\r
248 {\r
a6e97d28 249 BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);\r
250\r
251 if (OnlyArmBdsBootEntry && !IS_ARM_BDS_BOOTENTRY (BdsLoadOption)) {\r
252 continue;\r
253 }\r
254\r
c93ab96c 255 Print (L"[%d] %s\n", (BootOptionCount + 1), BdsLoadOption->Description);\r
ea46ebbe 256\r
257 DEBUG_CODE_BEGIN();\r
258 CHAR16* DevicePathTxt;\r
259 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
2ccfb71e 260 ARM_BDS_LOADER_TYPE LoaderType;\r
a6e97d28 261 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;\r
ea46ebbe 262\r
263 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
264 ASSERT_EFI_ERROR(Status);\r
a6e97d28 265 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BdsLoadOption->FilePathList,TRUE,TRUE);\r
ea46ebbe 266\r
267 Print(L"\t- %s\n",DevicePathTxt);\r
2ccfb71e 268 OptionalData = BdsLoadOption->OptionalData;\r
269 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);\r
270 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
271 Print (L"\t- Arguments: %a\n",&OptionalData->Arguments.LinuxArguments + 1);\r
ea46ebbe 272 }\r
273\r
274 FreePool(DevicePathTxt);\r
275 DEBUG_CODE_END();\r
276\r
277 BootOptionCount++;\r
278 }\r
279\r
c93ab96c 280 // Check if a valid boot option(s) is found\r
a6e97d28 281 if (BootOptionCount == 0) {\r
c93ab96c 282 if (StrCmp (InputStatement, DELETE_BOOT_ENTRY) == 0) {\r
283 Print (L"Nothing to remove!\n");\r
284 }else if (StrCmp (InputStatement, UPDATE_BOOT_ENTRY) == 0) {\r
285 Print (L"Couldn't find valid boot entries\n");\r
286 } else{\r
287 Print (L"No supported Boot Entry.\n");\r
288 }\r
289\r
a6e97d28 290 return EFI_NOT_FOUND;\r
291 }\r
292\r
ea46ebbe 293 // Get the index of the boot device to delete\r
294 BootOptionSelected = 0;\r
295 while (BootOptionSelected == 0) {\r
296 Print(InputStatement);\r
297 Status = GetHIInputInteger (&BootOptionSelected);\r
298 if (EFI_ERROR(Status)) {\r
299 return Status;\r
c93ab96c 300 } else if ((BootOptionSelected == 0) || (BootOptionSelected > BootOptionCount)) {\r
301 Print(L"Invalid input (max %d)\n",BootOptionCount);\r
ea46ebbe 302 BootOptionSelected = 0;\r
303 }\r
304 }\r
305\r
306 // Get the structure of the Boot device to delete\r
307 Index = 1;\r
308 for (Entry = GetFirstNode (BootOptionsList);\r
ff7666c5 309 !IsNull (BootOptionsList, Entry);\r
ea46ebbe 310 Entry = GetNextNode (BootOptionsList,Entry)\r
311 )\r
312 {\r
313 if (Index == BootOptionSelected) {\r
a6e97d28 314 *BdsLoadOptionEntry = LOAD_OPTION_ENTRY_FROM_LINK(Entry);\r
ea46ebbe 315 break;\r
316 }\r
317 Index++;\r
318 }\r
319\r
320 return EFI_SUCCESS;\r
321}\r
322\r
323EFI_STATUS\r
324BootMenuRemoveBootOption (\r
325 IN LIST_ENTRY *BootOptionsList\r
326 )\r
327{\r
a6e97d28 328 EFI_STATUS Status;\r
329 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;\r
ea46ebbe 330\r
11c20f4e 331 Status = BootMenuSelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, FALSE, &BootOptionEntry);\r
ea46ebbe 332 if (EFI_ERROR(Status)) {\r
333 return Status;\r
334 }\r
335\r
a6e97d28 336 // If the Boot Option was attached to a list remove it\r
337 if (!IsListEmpty (&BootOptionEntry->Link)) {\r
338 // Remove the entry from the list\r
339 RemoveEntryList (&BootOptionEntry->Link);\r
340 }\r
341\r
ea46ebbe 342 // Delete the BDS Load option structures\r
a6e97d28 343 BootOptionDelete (BootOptionEntry->BdsLoadOption);\r
ea46ebbe 344\r
345 return EFI_SUCCESS;\r
346}\r
347\r
348EFI_STATUS\r
349BootMenuUpdateBootOption (\r
350 IN LIST_ENTRY *BootOptionsList\r
351 )\r
352{\r
2ccfb71e 353 EFI_STATUS Status;\r
a6e97d28 354 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;\r
2ccfb71e 355 BDS_LOAD_OPTION *BootOption;\r
356 BDS_LOAD_OPTION_SUPPORT* DeviceSupport;\r
357 ARM_BDS_LOADER_ARGUMENTS* BootArguments;\r
74b96132 358 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
2ccfb71e 359 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];\r
14238a61 360 EFI_DEVICE_PATH *DevicePath;\r
361 EFI_DEVICE_PATH *TempInitrdPath;\r
2ccfb71e 362 ARM_BDS_LOADER_TYPE BootType;\r
363 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;\r
364 ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;\r
22a262c8 365 EFI_DEVICE_PATH *InitrdPathNode;\r
366 EFI_DEVICE_PATH *InitrdPath;\r
2ccfb71e 367 UINTN InitrdSize;\r
368 UINTN CmdLineSize;\r
22a262c8 369 BOOLEAN InitrdSupport;\r
ea46ebbe 370\r
11c20f4e 371 Status = BootMenuSelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, TRUE, &BootOptionEntry);\r
ea46ebbe 372 if (EFI_ERROR(Status)) {\r
373 return Status;\r
374 }\r
a6e97d28 375 BootOption = BootOptionEntry->BdsLoadOption;\r
ea46ebbe 376\r
377 // Get the device support for this Boot Option\r
22a262c8 378 Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport);\r
ea46ebbe 379 if (EFI_ERROR(Status)) {\r
ff7666c5 380 Print(L"Not possible to retrieve the supported device for the update\n");\r
ea46ebbe 381 return EFI_UNSUPPORTED;\r
382 }\r
383\r
22a262c8 384 Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath, NULL, NULL);\r
ea46ebbe 385 if (EFI_ERROR(Status)) {\r
386 Status = EFI_ABORTED;\r
387 goto EXIT;\r
388 }\r
389\r
2ccfb71e 390 OptionalData = BootOption->OptionalData;\r
391 BootType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((UINT32 *)(&OptionalData->Header.LoaderType));\r
656416bc 392\r
2ccfb71e 393 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
394 LinuxArguments = &OptionalData->Arguments.LinuxArguments;\r
395\r
396 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);\r
2ccfb71e 397\r
3e710183 398 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);\r
399 if (InitrdSize > 0) {\r
22a262c8 400 Print(L"Keep the initrd: ");\r
401 } else {\r
402 Print(L"Add an initrd: ");\r
403 }\r
404 Status = GetHIInputBoolean (&InitrdSupport);\r
405 if (EFI_ERROR(Status)) {\r
406 Status = EFI_ABORTED;\r
407 goto EXIT;\r
408 }\r
409\r
410 if (InitrdSupport) {\r
411 if (InitrdSize > 0) {\r
412 // Case we update the initrd device path\r
49a25d84 413 Status = DeviceSupport->UpdateDevicePathNode ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize), L"initrd", &InitrdPath, NULL, NULL);\r
22a262c8 414 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
415 Status = EFI_ABORTED;\r
416 goto EXIT;\r
417 }\r
418 InitrdSize = GetDevicePathSize (InitrdPath);\r
419 } else {\r
420 // Case we create the initrd device path\r
421\r
422 Status = DeviceSupport->CreateDevicePathNode (L"initrd", &InitrdPathNode, NULL, NULL);\r
423 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
424 Status = EFI_ABORTED;\r
425 goto EXIT;\r
426 }\r
427\r
428 if (InitrdPathNode != NULL) {\r
429 // Duplicate Linux kernel Device Path\r
14238a61 430 TempInitrdPath = DuplicateDevicePath (BootOption->FilePathList);\r
22a262c8 431 // Replace Linux kernel Node by EndNode\r
14238a61 432 SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath));\r
22a262c8 433 // Append the Device Path node to the select device path\r
14238a61 434 InitrdPath = AppendDevicePathNode (TempInitrdPath, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNode);\r
435 FreePool (TempInitrdPath);\r
436 InitrdSize = GetDevicePathSize (InitrdPath);\r
22a262c8 437 } else {\r
438 InitrdPath = NULL;\r
439 }\r
3e710183 440 }\r
22a262c8 441 } else {\r
442 InitrdSize = 0;\r
656416bc 443 }\r
444\r
aeaf64d6 445 Print(L"Arguments to pass to the binary: ");\r
2ccfb71e 446 if (CmdLineSize > 0) {\r
447 AsciiStrnCpy(CmdLine, (CONST CHAR8*)(LinuxArguments + 1), CmdLineSize);\r
656416bc 448 } else {\r
2ccfb71e 449 CmdLine[0] = '\0';\r
656416bc 450 }\r
2ccfb71e 451 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
656416bc 452 if (EFI_ERROR(Status)) {\r
453 Status = EFI_ABORTED;\r
454 goto FREE_DEVICE_PATH;\r
455 }\r
2ccfb71e 456\r
457 CmdLineSize = AsciiStrSize (CmdLine);\r
2ccfb71e 458\r
459 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool(sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize);\r
460 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;\r
461 BootArguments->LinuxArguments.InitrdSize = InitrdSize;\r
462 CopyMem (&BootArguments->LinuxArguments + 1, CmdLine, CmdLineSize);\r
49a25d84 463 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);\r
2ccfb71e 464 } else {\r
465 BootArguments = NULL;\r
ea46ebbe 466 }\r
467\r
468 Print(L"Description for this new Entry: ");\r
3e710183 469 StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX);\r
74b96132 470 Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
ea46ebbe 471 if (EFI_ERROR(Status)) {\r
472 Status = EFI_ABORTED;\r
473 goto FREE_DEVICE_PATH;\r
474 }\r
475\r
ea46ebbe 476 // Update the entry\r
2ccfb71e 477 Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, BootArguments);\r
ea46ebbe 478\r
ea46ebbe 479FREE_DEVICE_PATH:\r
480 FreePool (DevicePath);\r
481\r
482EXIT:\r
326d1df9 483 if (Status == EFI_ABORTED) {\r
484 Print(L"\n");\r
485 }\r
ea46ebbe 486 return Status;\r
487}\r
488\r
95b3580f 489EFI_STATUS\r
490UpdateFdtPath (\r
491 IN LIST_ENTRY *BootOptionsList\r
492 )\r
493{\r
c0658bd6 494 EFI_STATUS Status;\r
495 UINTN FdtDevicePathSize;\r
496 BDS_SUPPORTED_DEVICE *SupportedBootDevice;\r
497 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePathNode;\r
498 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePath;\r
95b3580f 499\r
500 Status = SelectBootDevice (&SupportedBootDevice);\r
501 if (EFI_ERROR(Status)) {\r
502 Status = EFI_ABORTED;\r
503 goto EXIT;\r
504 }\r
505\r
506 // Create the specific device path node\r
c0658bd6 507 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNode, NULL, NULL);\r
95b3580f 508 if (EFI_ERROR(Status)) {\r
509 Status = EFI_ABORTED;\r
510 goto EXIT;\r
511 }\r
512\r
513 if (FdtDevicePathNode != NULL) {\r
514 // Append the Device Path node to the select device path\r
515 FdtDevicePath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNode);\r
c0658bd6 516 FdtDevicePathSize = GetDevicePathSize (FdtDevicePath);\r
aeaf64d6 517 Status = gRT->SetVariable (\r
518 (CHAR16*)L"Fdt",\r
519 &gArmGlobalVariableGuid,\r
520 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
521 FdtDevicePathSize,\r
522 FdtDevicePath\r
523 );\r
95b3580f 524 ASSERT_EFI_ERROR(Status);\r
525 } else {\r
aeaf64d6 526 gRT->SetVariable (\r
527 (CHAR16*)L"Fdt",\r
528 &gArmGlobalVariableGuid,\r
529 EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
530 0,\r
531 NULL\r
532 );\r
95b3580f 533 ASSERT_EFI_ERROR(Status);\r
534 }\r
535\r
536EXIT:\r
537 if (Status == EFI_ABORTED) {\r
538 Print(L"\n");\r
539 }\r
540 FreePool(SupportedBootDevice);\r
541 return Status;\r
542}\r
543\r
ea46ebbe 544struct BOOT_MANAGER_ENTRY {\r
545 CONST CHAR16* Description;\r
546 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
547} BootManagerEntries[] = {\r
548 { L"Add Boot Device Entry", BootMenuAddBootOption },\r
549 { L"Update Boot Device Entry", BootMenuUpdateBootOption },\r
550 { L"Remove Boot Device Entry", BootMenuRemoveBootOption },\r
95b3580f 551 { L"Update FDT path", UpdateFdtPath },\r
ea46ebbe 552};\r
553\r
554EFI_STATUS\r
555BootMenuManager (\r
556 IN LIST_ENTRY *BootOptionsList\r
557 )\r
558{\r
559 UINTN Index;\r
560 UINTN OptionSelected;\r
561 UINTN BootManagerEntryCount;\r
562 EFI_STATUS Status;\r
563\r
564 BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);\r
565\r
566 while (TRUE) {\r
567 // Display Boot Manager menu\r
568 for (Index = 0; Index < BootManagerEntryCount; Index++) {\r
569 Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);\r
570 }\r
571 Print(L"[%d] Return to main menu\n",Index+1);\r
572\r
573 // Select which entry to call\r
574 Print(L"Choice: ");\r
575 Status = GetHIInputInteger (&OptionSelected);\r
576 if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {\r
326d1df9 577 if (EFI_ERROR(Status)) {\r
578 Print(L"\n");\r
579 }\r
ea46ebbe 580 return EFI_SUCCESS;\r
581 } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {\r
ff7666c5 582 BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);\r
ea46ebbe 583 }\r
584 }\r
11c20f4e 585 // Should never go here\r
ea46ebbe 586}\r
587\r
588EFI_STATUS\r
8213627e 589BootShell (\r
ea46ebbe 590 IN LIST_ENTRY *BootOptionsList\r
591 )\r
592{\r
593 EFI_STATUS Status;\r
594\r
595 // Start EFI Shell\r
8213627e 596 Status = BdsLoadApplication (mImageHandle, L"Shell", 0, NULL);\r
ea46ebbe 597 if (Status == EFI_NOT_FOUND) {\r
598 Print (L"Error: EFI Application not found.\n");\r
599 } else if (EFI_ERROR(Status)) {\r
600 Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);\r
601 }\r
602\r
603 return Status;\r
604}\r
605\r
606struct BOOT_MAIN_ENTRY {\r
607 CONST CHAR16* Description;\r
608 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
609} BootMainEntries[] = {\r
8213627e 610 { L"Shell", BootShell },\r
ea46ebbe 611 { L"Boot Manager", BootMenuManager },\r
612};\r
613\r
614\r
615EFI_STATUS\r
616BootMenuMain (\r
617 VOID\r
618 )\r
619{\r
2ccfb71e 620 LIST_ENTRY BootOptionsList;\r
621 UINTN OptionCount;\r
622 UINTN BootOptionCount;\r
623 EFI_STATUS Status;\r
624 LIST_ENTRY* Entry;\r
625 BDS_LOAD_OPTION* BootOption;\r
626 UINTN BootOptionSelected;\r
627 UINTN Index;\r
628 UINTN BootMainEntryCount;\r
ea46ebbe 629\r
e862cd50 630 BootOption = NULL;\r
ea46ebbe 631 BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);\r
a6caee65 632\r
ea46ebbe 633 while (TRUE) {\r
a6e97d28 634 // Get Boot#### list\r
635 BootOptionList (&BootOptionsList);\r
636\r
ea46ebbe 637 OptionCount = 1;\r
638\r
639 // Display the Boot options\r
640 for (Entry = GetFirstNode (&BootOptionsList);\r
641 !IsNull (&BootOptionsList,Entry);\r
642 Entry = GetNextNode (&BootOptionsList,Entry)\r
643 )\r
644 {\r
645 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
646\r
ff7666c5 647 Print(L"[%d] %s\n", OptionCount, BootOption->Description);\r
ea46ebbe 648\r
649 DEBUG_CODE_BEGIN();\r
650 CHAR16* DevicePathTxt;\r
651 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
2ccfb71e 652 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;\r
653 UINTN CmdLineSize;\r
3e710183 654 ARM_BDS_LOADER_TYPE LoaderType;\r
ea46ebbe 655\r
ff7666c5 656 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
aa95e2f7 657 if (EFI_ERROR(Status)) {\r
658 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)\r
659 DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));\r
660 return Status;\r
661 }\r
ff7666c5 662 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE);\r
ea46ebbe 663\r
664 Print(L"\t- %s\n",DevicePathTxt);\r
2ccfb71e 665\r
666 // If it is a supported BootEntry then print its details\r
667 if (IS_ARM_BDS_BOOTENTRY (BootOption)) {\r
668 OptionalData = BootOption->OptionalData;\r
669 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);\r
670 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
671 if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.InitrdSize) > 0) {\r
672 CmdLineSize = ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize);\r
673 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (\r
674 GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(&OptionalData->Arguments.LinuxArguments + 1) + CmdLineSize)), TRUE, TRUE);\r
675 Print(L"\t- Initrd: %s\n", DevicePathTxt);\r
676 }\r
677 Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1));\r
ea46ebbe 678 }\r
7135d76d 679\r
680 switch (LoaderType) {\r
681 case BDS_LOADER_EFI_APPLICATION:\r
682 Print(L"\t- LoaderType: EFI Application\n");\r
683 break;\r
684\r
685 case BDS_LOADER_KERNEL_LINUX_ATAG:\r
686 Print(L"\t- LoaderType: Linux kernel with ATAG support\n");\r
687 break;\r
688\r
689 case BDS_LOADER_KERNEL_LINUX_FDT:\r
690 Print(L"\t- LoaderType: Linux kernel with FDT support\n");\r
691 break;\r
692\r
693 default:\r
694 Print(L"\t- LoaderType: Not recognized (%d)\n", LoaderType);\r
695 }\r
ea46ebbe 696 }\r
ea46ebbe 697 FreePool(DevicePathTxt);\r
698 DEBUG_CODE_END();\r
699\r
700 OptionCount++;\r
701 }\r
702 BootOptionCount = OptionCount-1;\r
703\r
704 // Display the hardcoded Boot entries\r
705 for (Index = 0; Index < BootMainEntryCount; Index++) {\r
706 Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);\r
707 OptionCount++;\r
708 }\r
709\r
710 // Request the boot entry from the user\r
711 BootOptionSelected = 0;\r
712 while (BootOptionSelected == 0) {\r
713 Print(L"Start: ");\r
714 Status = GetHIInputInteger (&BootOptionSelected);\r
715 if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {\r
716 Print(L"Invalid input (max %d)\n",(OptionCount-1));\r
717 BootOptionSelected = 0;\r
718 }\r
719 }\r
720\r
721 // Start the selected entry\r
722 if (BootOptionSelected > BootOptionCount) {\r
723 // Start the hardcoded entry\r
724 Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);\r
725 } else {\r
726 // Find the selected entry from the Boot#### list\r
727 Index = 1;\r
728 for (Entry = GetFirstNode (&BootOptionsList);\r
729 !IsNull (&BootOptionsList,Entry);\r
730 Entry = GetNextNode (&BootOptionsList,Entry)\r
731 )\r
732 {\r
733 if (Index == BootOptionSelected) {\r
734 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
735 break;\r
736 }\r
737 Index++;\r
738 }\r
739\r
740 Status = BootOptionStart (BootOption);\r
741 }\r
742 }\r
11c20f4e 743 // Should never go here\r
ea46ebbe 744}\r