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