ArmPlatformPkg/Bds: Corrected boot type detection
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootMenu.c
CommitLineData
ea46ebbe 1/** @file\r
2*\r
3b3b72d6 3* Copyright (c) 2011 - 2014, ARM Limited. All rights reserved.\r
ea46ebbe 4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "BdsInternal.h"\r
16\r
aeaf64d6 17#include <Guid/ArmGlobalVariableHob.h>\r
18\r
ea46ebbe 19extern 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
889ac6a8 149 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application or the kernel", &DevicePathNodes);\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
889ac6a8 161 if (SupportedBootDevice->Support->RequestBootType) {\r
55a9f75d
OM
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
2ccfb71e 171 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
22a262c8 172 Print(L"Add an initrd: ");\r
173 Status = GetHIInputBoolean (&InitrdSupport);\r
174 if (EFI_ERROR(Status)) {\r
656416bc 175 Status = EFI_ABORTED;\r
176 goto EXIT;\r
177 }\r
178\r
22a262c8 179 if (InitrdSupport) {\r
180 // Create the specific device path node\r
889ac6a8 181 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"initrd", &InitrdPathNodes);\r
22a262c8 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
ecc62d13 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
22a262c8 194 } else {\r
195 InitrdPath = NULL;\r
196 }\r
656416bc 197 } else {\r
2ccfb71e 198 InitrdPath = NULL;\r
656416bc 199 }\r
200\r
201 Print(L"Arguments to pass to the binary: ");\r
06044819 202 Status = GetHIInputAscii (AsciiCmdLine, BOOT_DEVICE_OPTION_MAX);\r
656416bc 203 if (EFI_ERROR(Status)) {\r
204 Status = EFI_ABORTED;\r
205 goto FREE_DEVICE_PATH;\r
206 }\r
2ccfb71e 207\r
06044819 208 CmdLineSize = AsciiStrSize (AsciiCmdLine);\r
2ccfb71e 209 InitrdSize = GetDevicePathSize (InitrdPath);\r
210\r
90a44ec4
OM
211 OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize;\r
212 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize);\r
aeaf64d6 213\r
2ccfb71e 214 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;\r
215 BootArguments->LinuxArguments.InitrdSize = InitrdSize;\r
5382a857 216 CopyMem ((VOID*)(&BootArguments->LinuxArguments + 1), AsciiCmdLine, CmdLineSize);\r
2ccfb71e 217 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);\r
90a44ec4
OM
218\r
219 OptionalData = (UINT8*)BootArguments;\r
2ccfb71e 220 } else {\r
06044819
OM
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
ea46ebbe 230 }\r
231\r
232 Print(L"Description for this new Entry: ");\r
74b96132 233 Status = GetHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
ea46ebbe 234 if (EFI_ERROR(Status)) {\r
235 Status = EFI_ABORTED;\r
236 goto FREE_DEVICE_PATH;\r
237 }\r
238\r
ea46ebbe 239 // Create new entry\r
a6e97d28 240 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY));\r
90a44ec4 241 Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize, &BdsLoadOptionEntry->BdsLoadOption);\r
ea46ebbe 242 if (!EFI_ERROR(Status)) {\r
a6e97d28 243 InsertTailList (BootOptionsList, &BdsLoadOptionEntry->Link);\r
ea46ebbe 244 }\r
245\r
ea46ebbe 246FREE_DEVICE_PATH:\r
247 FreePool (DevicePath);\r
248\r
249EXIT:\r
656416bc 250 if (Status == EFI_ABORTED) {\r
251 Print(L"\n");\r
252 }\r
253 FreePool(SupportedBootDevice);\r
ea46ebbe 254 return Status;\r
255}\r
256\r
257STATIC\r
258EFI_STATUS\r
259BootMenuSelectBootOption (\r
a6e97d28 260 IN LIST_ENTRY* BootOptionsList,\r
261 IN CONST CHAR16* InputStatement,\r
a6e97d28 262 OUT BDS_LOAD_OPTION_ENTRY** BdsLoadOptionEntry\r
ea46ebbe 263 )\r
264{\r
a6e97d28 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
3b3b72d6 271 BOOLEAN IsUnicode;\r
ea46ebbe 272\r
273 // Display the list of supported boot devices\r
c93ab96c 274 BootOptionCount = 0;\r
ea46ebbe 275 for (Entry = GetFirstNode (BootOptionsList);\r
276 !IsNull (BootOptionsList,Entry);\r
a6e97d28 277 Entry = GetNextNode (BootOptionsList, Entry)\r
ea46ebbe 278 )\r
279 {\r
a6e97d28 280 BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);\r
281\r
c93ab96c 282 Print (L"[%d] %s\n", (BootOptionCount + 1), BdsLoadOption->Description);\r
ea46ebbe 283\r
284 DEBUG_CODE_BEGIN();\r
285 CHAR16* DevicePathTxt;\r
286 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
2ccfb71e 287 ARM_BDS_LOADER_TYPE LoaderType;\r
a6e97d28 288 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;\r
ea46ebbe 289\r
290 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
291 ASSERT_EFI_ERROR(Status);\r
a6e97d28 292 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BdsLoadOption->FilePathList,TRUE,TRUE);\r
ea46ebbe 293\r
294 Print(L"\t- %s\n",DevicePathTxt);\r
2ccfb71e 295 OptionalData = BdsLoadOption->OptionalData;\r
3b3b72d6
OM
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
ea46ebbe 309 }\r
310\r
311 FreePool(DevicePathTxt);\r
312 DEBUG_CODE_END();\r
313\r
314 BootOptionCount++;\r
315 }\r
316\r
c93ab96c 317 // Check if a valid boot option(s) is found\r
a6e97d28 318 if (BootOptionCount == 0) {\r
c93ab96c 319 if (StrCmp (InputStatement, DELETE_BOOT_ENTRY) == 0) {\r
320 Print (L"Nothing to remove!\n");\r
ecc62d13 321 } else if (StrCmp (InputStatement, UPDATE_BOOT_ENTRY) == 0) {\r
c93ab96c 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
a6e97d28 327 return EFI_NOT_FOUND;\r
328 }\r
329\r
ea46ebbe 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
c93ab96c 337 } else if ((BootOptionSelected == 0) || (BootOptionSelected > BootOptionCount)) {\r
338 Print(L"Invalid input (max %d)\n",BootOptionCount);\r
ea46ebbe 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
ff7666c5 346 !IsNull (BootOptionsList, Entry);\r
ea46ebbe 347 Entry = GetNextNode (BootOptionsList,Entry)\r
348 )\r
349 {\r
350 if (Index == BootOptionSelected) {\r
a6e97d28 351 *BdsLoadOptionEntry = LOAD_OPTION_ENTRY_FROM_LINK(Entry);\r
ea46ebbe 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
a6e97d28 365 EFI_STATUS Status;\r
366 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;\r
ea46ebbe 367\r
3b3b72d6 368 Status = BootMenuSelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, &BootOptionEntry);\r
ea46ebbe 369 if (EFI_ERROR(Status)) {\r
370 return Status;\r
371 }\r
372\r
a6e97d28 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
ea46ebbe 379 // Delete the BDS Load option structures\r
a6e97d28 380 BootOptionDelete (BootOptionEntry->BdsLoadOption);\r
ea46ebbe 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
2ccfb71e 390 EFI_STATUS Status;\r
a6e97d28 391 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;\r
2ccfb71e 392 BDS_LOAD_OPTION *BootOption;\r
393 BDS_LOAD_OPTION_SUPPORT* DeviceSupport;\r
394 ARM_BDS_LOADER_ARGUMENTS* BootArguments;\r
74b96132 395 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
2ccfb71e 396 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];\r
3b3b72d6 397 CHAR16 UnicodeCmdLine[BOOT_DEVICE_OPTION_MAX];\r
14238a61 398 EFI_DEVICE_PATH *DevicePath;\r
399 EFI_DEVICE_PATH *TempInitrdPath;\r
2ccfb71e 400 ARM_BDS_LOADER_TYPE BootType;\r
90a44ec4 401 ARM_BDS_LOADER_OPTIONAL_DATA* LoaderOptionalData;\r
2ccfb71e 402 ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;\r
ecc62d13 403 EFI_DEVICE_PATH *InitrdPathNodes;\r
22a262c8 404 EFI_DEVICE_PATH *InitrdPath;\r
2ccfb71e 405 UINTN InitrdSize;\r
406 UINTN CmdLineSize;\r
22a262c8 407 BOOLEAN InitrdSupport;\r
90a44ec4
OM
408 UINT8* OptionalData;\r
409 UINTN OptionalDataSize;\r
3b3b72d6
OM
410 BOOLEAN IsPrintable;\r
411 BOOLEAN IsUnicode;\r
ea46ebbe 412\r
3b3b72d6 413 Status = BootMenuSelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry);\r
ea46ebbe 414 if (EFI_ERROR(Status)) {\r
415 return Status;\r
416 }\r
a6e97d28 417 BootOption = BootOptionEntry->BdsLoadOption;\r
ea46ebbe 418\r
419 // Get the device support for this Boot Option\r
22a262c8 420 Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport);\r
ea46ebbe 421 if (EFI_ERROR(Status)) {\r
ff7666c5 422 Print(L"Not possible to retrieve the supported device for the update\n");\r
ea46ebbe 423 return EFI_UNSUPPORTED;\r
424 }\r
425\r
889ac6a8 426 Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath);\r
ea46ebbe 427 if (EFI_ERROR(Status)) {\r
428 Status = EFI_ABORTED;\r
429 goto EXIT;\r
430 }\r
431\r
889ac6a8 432 if (DeviceSupport->RequestBootType) {\r
55a9f75d
OM
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
90a44ec4 440 LoaderOptionalData = BootOption->OptionalData;\r
3b3b72d6
OM
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
656416bc 446\r
2ccfb71e 447 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {\r
90a44ec4 448 LinuxArguments = &LoaderOptionalData->Arguments.LinuxArguments;\r
2ccfb71e 449\r
450 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);\r
2ccfb71e 451\r
3e710183 452 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);\r
453 if (InitrdSize > 0) {\r
22a262c8 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
889ac6a8 467 Status = DeviceSupport->UpdateDevicePathNode ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize), L"initrd", &InitrdPath);\r
22a262c8 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
889ac6a8 476 Status = DeviceSupport->CreateDevicePathNode (L"initrd", &InitrdPathNodes);\r
22a262c8 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
ecc62d13 482 if (InitrdPathNodes != NULL) {\r
22a262c8 483 // Duplicate Linux kernel Device Path\r
14238a61 484 TempInitrdPath = DuplicateDevicePath (BootOption->FilePathList);\r
22a262c8 485 // Replace Linux kernel Node by EndNode\r
14238a61 486 SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath));\r
ecc62d13 487 // Append the Device Path to the selected device path\r
488 InitrdPath = AppendDevicePath (TempInitrdPath, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes);\r
14238a61 489 FreePool (TempInitrdPath);\r
ecc62d13 490 if (InitrdPath == NULL) {\r
491 Status = EFI_OUT_OF_RESOURCES;\r
492 goto EXIT;\r
493 }\r
14238a61 494 InitrdSize = GetDevicePathSize (InitrdPath);\r
22a262c8 495 } else {\r
496 InitrdPath = NULL;\r
497 }\r
3e710183 498 }\r
22a262c8 499 } else {\r
500 InitrdSize = 0;\r
656416bc 501 }\r
502\r
aeaf64d6 503 Print(L"Arguments to pass to the binary: ");\r
2ccfb71e 504 if (CmdLineSize > 0) {\r
505 AsciiStrnCpy(CmdLine, (CONST CHAR8*)(LinuxArguments + 1), CmdLineSize);\r
656416bc 506 } else {\r
2ccfb71e 507 CmdLine[0] = '\0';\r
656416bc 508 }\r
2ccfb71e 509 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);\r
656416bc 510 if (EFI_ERROR(Status)) {\r
511 Status = EFI_ABORTED;\r
512 goto FREE_DEVICE_PATH;\r
513 }\r
2ccfb71e 514\r
515 CmdLineSize = AsciiStrSize (CmdLine);\r
2ccfb71e 516\r
90a44ec4
OM
517 OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize;\r
518 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize);\r
2ccfb71e 519 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;\r
520 BootArguments->LinuxArguments.InitrdSize = InitrdSize;\r
521 CopyMem (&BootArguments->LinuxArguments + 1, CmdLine, CmdLineSize);\r
49a25d84 522 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);\r
90a44ec4
OM
523\r
524 OptionalData = (UINT8*)BootArguments;\r
2ccfb71e 525 } else {\r
3b3b72d6
OM
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
ea46ebbe 569 }\r
570\r
571 Print(L"Description for this new Entry: ");\r
3e710183 572 StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX);\r
74b96132 573 Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);\r
ea46ebbe 574 if (EFI_ERROR(Status)) {\r
575 Status = EFI_ABORTED;\r
576 goto FREE_DEVICE_PATH;\r
577 }\r
578\r
ea46ebbe 579 // Update the entry\r
90a44ec4 580 Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize);\r
ea46ebbe 581\r
ea46ebbe 582FREE_DEVICE_PATH:\r
583 FreePool (DevicePath);\r
584\r
585EXIT:\r
326d1df9 586 if (Status == EFI_ABORTED) {\r
587 Print(L"\n");\r
588 }\r
ea46ebbe 589 return Status;\r
590}\r
591\r
95b3580f 592EFI_STATUS\r
593UpdateFdtPath (\r
594 IN LIST_ENTRY *BootOptionsList\r
595 )\r
596{\r
c0658bd6 597 EFI_STATUS Status;\r
598 UINTN FdtDevicePathSize;\r
599 BDS_SUPPORTED_DEVICE *SupportedBootDevice;\r
ecc62d13 600 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePathNodes;\r
c0658bd6 601 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePath;\r
95b3580f 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
889ac6a8 610 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNodes);\r
95b3580f 611 if (EFI_ERROR(Status)) {\r
612 Status = EFI_ABORTED;\r
613 goto EXIT;\r
614 }\r
615\r
ecc62d13 616 if (FdtDevicePathNodes != NULL) {\r
95b3580f 617 // Append the Device Path node to the select device path\r
ecc62d13 618 FdtDevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNodes);\r
c0658bd6 619 FdtDevicePathSize = GetDevicePathSize (FdtDevicePath);\r
aeaf64d6 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
95b3580f 627 ASSERT_EFI_ERROR(Status);\r
628 } else {\r
aeaf64d6 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
95b3580f 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
42de0937
RC
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
ea46ebbe 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
95b3580f 702 { L"Update FDT path", UpdateFdtPath },\r
42de0937 703 { L"Set Boot Timeout", BootMenuSetBootTimeout },\r
ea46ebbe 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
326d1df9 729 if (EFI_ERROR(Status)) {\r
730 Print(L"\n");\r
731 }\r
ea46ebbe 732 return EFI_SUCCESS;\r
733 } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {\r
ff7666c5 734 BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);\r
ea46ebbe 735 }\r
736 }\r
11c20f4e 737 // Should never go here\r
ea46ebbe 738}\r
739\r
740EFI_STATUS\r
8213627e 741BootShell (\r
ea46ebbe 742 IN LIST_ENTRY *BootOptionsList\r
743 )\r
744{\r
745 EFI_STATUS Status;\r
746\r
747 // Start EFI Shell\r
8213627e 748 Status = BdsLoadApplication (mImageHandle, L"Shell", 0, NULL);\r
ea46ebbe 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
8213627e 762 { L"Shell", BootShell },\r
ea46ebbe 763 { L"Boot Manager", BootMenuManager },\r
764};\r
765\r
766\r
767EFI_STATUS\r
768BootMenuMain (\r
769 VOID\r
770 )\r
771{\r
2ccfb71e 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
5389972a 781 BOOLEAN IsUnicode;\r
ea46ebbe 782\r
5389972a 783 BootOption = NULL;\r
ea46ebbe 784 BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);\r
a6caee65 785\r
ea46ebbe 786 while (TRUE) {\r
a6e97d28 787 // Get Boot#### list\r
788 BootOptionList (&BootOptionsList);\r
789\r
ea46ebbe 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
ff7666c5 800 Print(L"[%d] %s\n", OptionCount, BootOption->Description);\r
ea46ebbe 801\r
802 DEBUG_CODE_BEGIN();\r
803 CHAR16* DevicePathTxt;\r
804 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
2ccfb71e 805 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;\r
806 UINTN CmdLineSize;\r
3e710183 807 ARM_BDS_LOADER_TYPE LoaderType;\r
ea46ebbe 808\r
ff7666c5 809 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
aa95e2f7 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
ff7666c5 815 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE);\r
ea46ebbe 816\r
817 Print(L"\t- %s\n",DevicePathTxt);\r
2ccfb71e 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
5aecd343
OM
830 if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize) > 0) {\r
831 Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1));\r
832 }\r
ea46ebbe 833 }\r
7135d76d 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
5389972a
OM
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
ea46ebbe 859 }\r
ea46ebbe 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
11c20f4e 906 // Should never go here\r
ea46ebbe 907}\r