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