]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPlatformPkg/Bds/BootMenu.c
ArmPlatformPkg/PrePiHobListPointerLib: Fixed pointer calculation
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootMenu.c
CommitLineData
ea46ebbe 1/** @file\r
2*\r
3* Copyright (c) 2011, ARM Limited. All rights reserved.\r
4*\r
5* This program and the accompanying materials\r
6* are licensed and made available under the terms and conditions of the BSD License\r
7* which accompanies this distribution. The full text of the license may be found at\r
8* http://opensource.org/licenses/bsd-license.php\r
9*\r
10* THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11* WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12*\r
13**/\r
14\r
15#include "BdsInternal.h"\r
16\r
17extern EFI_HANDLE mImageHandle;\r
18extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;\r
19\r
20EFI_STATUS\r
21BootMenuAddBootOption (\r
22 IN LIST_ENTRY *BootOptionsList\r
23 )\r
24{\r
25 EFI_STATUS Status;\r
26 LIST_ENTRY SupportedDeviceList;\r
27 UINTN SupportedDeviceCount;\r
28 BDS_SUPPORTED_DEVICE* SupportedBootDevice;\r
29 LIST_ENTRY* Entry;\r
30 UINTN SupportedDeviceSelected;\r
31 CHAR8 AsciiBootOption[BOOT_DEVICE_OPTION_MAX];\r
32 CHAR8 AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
33 CHAR16 *BootDescription;\r
34 UINT32 Attributes;\r
35 BDS_LOADER_TYPE BootType;\r
36 UINTN Index;\r
37 BDS_LOAD_OPTION *BdsLoadOption;\r
38 EFI_DEVICE_PATH* DevicePath;\r
39 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r
40\r
e862cd50 41 Attributes = 0;\r
42 SupportedBootDevice = NULL;\r
ea46ebbe 43\r
44 //\r
45 // List the Boot Devices supported\r
46 //\r
47\r
48 // Start all the drivers first\r
49 BdsConnectAllDrivers ();\r
50\r
51 // List the supported devices\r
52 Status = BootDeviceListSupportedInit (&SupportedDeviceList);\r
53 ASSERT_EFI_ERROR(Status);\r
54\r
55 SupportedDeviceCount = 0;\r
56 for (Entry = GetFirstNode (&SupportedDeviceList);\r
57 !IsNull (&SupportedDeviceList,Entry);\r
58 Entry = GetNextNode (&SupportedDeviceList,Entry)\r
59 )\r
60 {\r
61 SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
62 Print(L"[%d] %s\n",SupportedDeviceCount+1,SupportedBootDevice->Description);\r
63\r
64 DEBUG_CODE_BEGIN();\r
65 CHAR16* DevicePathTxt;\r
66 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
67\r
68 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
69 ASSERT_EFI_ERROR(Status);\r
70 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(SupportedBootDevice->DevicePathProtocol,TRUE,TRUE);\r
71\r
72 Print(L"\t- %s\n",DevicePathTxt);\r
73\r
74 FreePool(DevicePathTxt);\r
75 DEBUG_CODE_END();\r
76\r
77 SupportedDeviceCount++;\r
78 }\r
79\r
80 if (SupportedDeviceCount == 0) {\r
81 Print(L"There is no supported device.\n");\r
82 Status = EFI_ABORTED;\r
83 goto EXIT;\r
84 }\r
85\r
86 //\r
87 // Select the Boot Device\r
88 //\r
89 SupportedDeviceSelected = 0;\r
90 while (SupportedDeviceSelected == 0) {\r
91 Print(L"Select the Boot Device: ");\r
92 Status = GetHIInputInteger (&SupportedDeviceSelected);\r
93 if (EFI_ERROR(Status)) {\r
94 Status = EFI_ABORTED;\r
95 goto EXIT;\r
96 } else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) {\r
97 Print(L"Invalid input (max %d)\n",SupportedDeviceSelected);\r
98 SupportedDeviceSelected = 0;\r
99 }\r
100 }\r
101\r
102 //\r
103 // Get the Device Path for the selected boot device\r
104 //\r
105 Index = 1;\r
106 for (Entry = GetFirstNode (&SupportedDeviceList);\r
107 !IsNull (&SupportedDeviceList,Entry);\r
108 Entry = GetNextNode (&SupportedDeviceList,Entry)\r
109 )\r
110 {\r
111 if (Index == SupportedDeviceSelected) {\r
112 SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r
113 break;\r
114 }\r
115 Index++;\r
116 }\r
117\r
118 // Create the specific device path node\r
119 Status = SupportedBootDevice->Support->CreateDevicePathNode (SupportedBootDevice, &DevicePathNode, &BootType, &Attributes);\r
120 if (EFI_ERROR(Status)) {\r
121 Status = EFI_ABORTED;\r
122 goto EXIT;\r
123 }\r
124 // Append the Device Path node to the select device path\r
125 DevicePath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNode);\r
126\r
127 Print(L"Arguments to pass to the binary: ");\r
128 Status = GetHIInputAscii (AsciiBootOption,BOOT_DEVICE_OPTION_MAX);\r
129 if (EFI_ERROR(Status)) {\r
130 Status = EFI_ABORTED;\r
131 goto FREE_DEVICE_PATH;\r
132 }\r
133\r
134 Print(L"Description for this new Entry: ");\r
135 Status = GetHIInputAscii (AsciiBootDescription,BOOT_DEVICE_DESCRIPTION_MAX);\r
136 if (EFI_ERROR(Status)) {\r
137 Status = EFI_ABORTED;\r
138 goto FREE_DEVICE_PATH;\r
139 }\r
140\r
141 // Convert Ascii into Unicode\r
142 BootDescription = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootDescription) * sizeof(CHAR16));\r
143 AsciiStrToUnicodeStr (AsciiBootDescription, BootDescription);\r
144\r
145 // Create new entry\r
146 Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, AsciiBootOption, &BdsLoadOption);\r
147 if (!EFI_ERROR(Status)) {\r
148 InsertTailList (BootOptionsList,&BdsLoadOption->Link);\r
149 }\r
150\r
151 FreePool (BootDescription);\r
152\r
153FREE_DEVICE_PATH:\r
154 FreePool (DevicePath);\r
155\r
156EXIT:\r
157 BootDeviceListSupportedFree (&SupportedDeviceList);\r
158 return Status;\r
159}\r
160\r
161STATIC\r
162EFI_STATUS\r
163BootMenuSelectBootOption (\r
164 IN LIST_ENTRY *BootOptionsList,\r
165 IN CONST CHAR16* InputStatement,\r
166 OUT BDS_LOAD_OPTION **BdsLoadOption\r
167 )\r
168{\r
169 EFI_STATUS Status;\r
170 LIST_ENTRY* Entry;\r
171 BDS_LOAD_OPTION *BootOption;\r
172 UINTN BootOptionSelected;\r
173 UINTN BootOptionCount;\r
174 UINTN Index;\r
175\r
176 // Display the list of supported boot devices\r
177 BootOptionCount = 1;\r
178 for (Entry = GetFirstNode (BootOptionsList);\r
179 !IsNull (BootOptionsList,Entry);\r
180 Entry = GetNextNode (BootOptionsList,Entry)\r
181 )\r
182 {\r
183 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
184 Print(L"[%d] %s\n",BootOptionCount,BootOption->Description);\r
185\r
186 DEBUG_CODE_BEGIN();\r
187 CHAR16* DevicePathTxt;\r
188 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
189\r
190 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
191 ASSERT_EFI_ERROR(Status);\r
192 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);\r
193\r
194 Print(L"\t- %s\n",DevicePathTxt);\r
195 if ((BootOption->OptionalData != NULL) && (BootOption->OptionalData->Arguments != NULL)) {\r
196 Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments);\r
197 }\r
198\r
199 FreePool(DevicePathTxt);\r
200 DEBUG_CODE_END();\r
201\r
202 BootOptionCount++;\r
203 }\r
204\r
205 // Get the index of the boot device to delete\r
206 BootOptionSelected = 0;\r
207 while (BootOptionSelected == 0) {\r
208 Print(InputStatement);\r
209 Status = GetHIInputInteger (&BootOptionSelected);\r
210 if (EFI_ERROR(Status)) {\r
211 return Status;\r
212 } else if ((BootOptionSelected == 0) || (BootOptionSelected >= BootOptionCount)) {\r
213 Print(L"Invalid input (max %d)\n",BootOptionCount);\r
214 BootOptionSelected = 0;\r
215 }\r
216 }\r
217\r
218 // Get the structure of the Boot device to delete\r
219 Index = 1;\r
220 for (Entry = GetFirstNode (BootOptionsList);\r
221 !IsNull (BootOptionsList,Entry);\r
222 Entry = GetNextNode (BootOptionsList,Entry)\r
223 )\r
224 {\r
225 if (Index == BootOptionSelected) {\r
226 *BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);\r
227 break;\r
228 }\r
229 Index++;\r
230 }\r
231\r
232 return EFI_SUCCESS;\r
233}\r
234\r
235EFI_STATUS\r
236BootMenuRemoveBootOption (\r
237 IN LIST_ENTRY *BootOptionsList\r
238 )\r
239{\r
240 EFI_STATUS Status;\r
241 BDS_LOAD_OPTION *BootOption;\r
242\r
243 Status = BootMenuSelectBootOption (BootOptionsList,L"Delete entry: ",&BootOption);\r
244 if (EFI_ERROR(Status)) {\r
245 return Status;\r
246 }\r
247\r
248 // Delete the BDS Load option structures\r
249 BootOptionDelete (BootOption);\r
250\r
251 return EFI_SUCCESS;\r
252}\r
253\r
254EFI_STATUS\r
255BootMenuUpdateBootOption (\r
256 IN LIST_ENTRY *BootOptionsList\r
257 )\r
258{\r
259 EFI_STATUS Status;\r
260 BDS_LOAD_OPTION *BootOption;\r
261 BDS_LOAD_OPTION_SUPPORT* DeviceSupport;\r
262 CHAR8 AsciiBootOption[BOOT_DEVICE_OPTION_MAX];\r
263 CHAR8 AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r
264 CHAR16 *BootDescription;\r
265 EFI_DEVICE_PATH* DevicePath;\r
266 UINT32 Attributes;\r
267 BDS_LOADER_TYPE BootType;\r
268\r
269 Status = BootMenuSelectBootOption (BootOptionsList,L"Update entry: ",&BootOption);\r
270 if (EFI_ERROR(Status)) {\r
271 return Status;\r
272 }\r
273\r
274 // Get the device support for this Boot Option\r
275 Status = BootDeviceGetDeviceSupport (BootOption,&DeviceSupport);\r
276 if (EFI_ERROR(Status)) {\r
277 Print(L"Impossible to retrieve the supported device for the update\n");\r
278 return EFI_UNSUPPORTED;\r
279 }\r
280\r
281 Status = DeviceSupport->UpdateDevicePathNode (BootOption,&DevicePath,&BootType,&Attributes);\r
282 if (EFI_ERROR(Status)) {\r
283 Status = EFI_ABORTED;\r
284 goto EXIT;\r
285 }\r
286\r
287 Print(L"Arguments to pass to the binary: ");\r
288 if (BootOption->OptionalData) {\r
289 AsciiStrnCpy(AsciiBootOption,BootOption->OptionalData->Arguments,BOOT_DEVICE_FILEPATH_MAX);\r
290 } else {\r
291 AsciiBootOption[0] = '\0';\r
292 }\r
293 Status = EditHIInputAscii (AsciiBootOption,BOOT_DEVICE_OPTION_MAX);\r
294 if (EFI_ERROR(Status)) {\r
295 Status = EFI_ABORTED;\r
296 goto FREE_DEVICE_PATH;\r
297 }\r
298\r
299 Print(L"Description for this new Entry: ");\r
300 UnicodeStrToAsciiStr (BootOption->Description,AsciiBootDescription);\r
301 Status = EditHIInputAscii (AsciiBootDescription,BOOT_DEVICE_DESCRIPTION_MAX);\r
302 if (EFI_ERROR(Status)) {\r
303 Status = EFI_ABORTED;\r
304 goto FREE_DEVICE_PATH;\r
305 }\r
306\r
307 // Convert Ascii into Unicode\r
308 BootDescription = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootDescription) * sizeof(CHAR16));\r
309 AsciiStrToUnicodeStr (AsciiBootDescription, BootDescription);\r
310\r
311 // Update the entry\r
312 Status = BootOptionUpdate (BootOption, Attributes, BootDescription, DevicePath, BootType, AsciiBootOption);\r
313\r
314 FreePool (BootDescription);\r
315\r
316FREE_DEVICE_PATH:\r
317 FreePool (DevicePath);\r
318\r
319EXIT:\r
320 return Status;\r
321}\r
322\r
323struct BOOT_MANAGER_ENTRY {\r
324 CONST CHAR16* Description;\r
325 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
326} BootManagerEntries[] = {\r
327 { L"Add Boot Device Entry", BootMenuAddBootOption },\r
328 { L"Update Boot Device Entry", BootMenuUpdateBootOption },\r
329 { L"Remove Boot Device Entry", BootMenuRemoveBootOption },\r
330};\r
331\r
332EFI_STATUS\r
333BootMenuManager (\r
334 IN LIST_ENTRY *BootOptionsList\r
335 )\r
336{\r
337 UINTN Index;\r
338 UINTN OptionSelected;\r
339 UINTN BootManagerEntryCount;\r
340 EFI_STATUS Status;\r
341\r
342 BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);\r
343\r
344 while (TRUE) {\r
345 // Display Boot Manager menu\r
346 for (Index = 0; Index < BootManagerEntryCount; Index++) {\r
347 Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);\r
348 }\r
349 Print(L"[%d] Return to main menu\n",Index+1);\r
350\r
351 // Select which entry to call\r
352 Print(L"Choice: ");\r
353 Status = GetHIInputInteger (&OptionSelected);\r
354 if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {\r
355 return EFI_SUCCESS;\r
356 } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {\r
357 Status = BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);\r
358 }\r
359 }\r
360\r
361 return EFI_SUCCESS;\r
362}\r
363\r
364EFI_STATUS\r
365BootEBL (\r
366 IN LIST_ENTRY *BootOptionsList\r
367 )\r
368{\r
369 EFI_STATUS Status;\r
370\r
371 // Start EFI Shell\r
372 Status = BdsLoadApplication(mImageHandle, L"Ebl");\r
373 if (Status == EFI_NOT_FOUND) {\r
374 Print (L"Error: EFI Application not found.\n");\r
375 } else if (EFI_ERROR(Status)) {\r
376 Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);\r
377 }\r
378\r
379 return Status;\r
380}\r
381\r
382struct BOOT_MAIN_ENTRY {\r
383 CONST CHAR16* Description;\r
384 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r
385} BootMainEntries[] = {\r
386 { L"EBL", BootEBL },\r
387 { L"Boot Manager", BootMenuManager },\r
388};\r
389\r
390\r
391EFI_STATUS\r
392BootMenuMain (\r
393 VOID\r
394 )\r
395{\r
396 LIST_ENTRY BootOptionsList;\r
397 UINTN OptionCount;\r
398 UINTN BootOptionCount;\r
399 EFI_STATUS Status;\r
400 LIST_ENTRY *Entry;\r
401 BDS_LOAD_OPTION *BootOption;\r
402 UINTN BootOptionSelected;\r
403 UINTN Index;\r
404 UINTN BootMainEntryCount;\r
405\r
e862cd50 406 BootOption = NULL;\r
ea46ebbe 407 BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);\r
a6caee65 408\r
ea46ebbe 409 // Get Boot#### list\r
410 BootOptionList (&BootOptionsList);\r
411\r
412 while (TRUE) {\r
413 OptionCount = 1;\r
414\r
415 // Display the Boot options\r
416 for (Entry = GetFirstNode (&BootOptionsList);\r
417 !IsNull (&BootOptionsList,Entry);\r
418 Entry = GetNextNode (&BootOptionsList,Entry)\r
419 )\r
420 {\r
421 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
422\r
423 Print(L"[%d] %s\n",OptionCount,BootOption->Description);\r
424\r
425 DEBUG_CODE_BEGIN();\r
426 CHAR16* DevicePathTxt;\r
427 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r
428\r
429 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r
aa95e2f7 430 if (EFI_ERROR(Status)) {\r
431 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)\r
432 DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));\r
433 return Status;\r
434 }\r
ea46ebbe 435 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);\r
436\r
437 Print(L"\t- %s\n",DevicePathTxt);\r
438 if (BootOption->OptionalData != NULL) {\r
c60ea9a8 439 Print(L"\t- LoaderType: %d\n", ReadUnaligned32 (&BootOption->OptionalData->LoaderType));\r
ea46ebbe 440 if (BootOption->OptionalData->Arguments != NULL) {\r
441 Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments);\r
442 }\r
443 }\r
444\r
445 FreePool(DevicePathTxt);\r
446 DEBUG_CODE_END();\r
447\r
448 OptionCount++;\r
449 }\r
450 BootOptionCount = OptionCount-1;\r
451\r
452 // Display the hardcoded Boot entries\r
453 for (Index = 0; Index < BootMainEntryCount; Index++) {\r
454 Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);\r
455 OptionCount++;\r
456 }\r
457\r
458 // Request the boot entry from the user\r
459 BootOptionSelected = 0;\r
460 while (BootOptionSelected == 0) {\r
461 Print(L"Start: ");\r
462 Status = GetHIInputInteger (&BootOptionSelected);\r
463 if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {\r
464 Print(L"Invalid input (max %d)\n",(OptionCount-1));\r
465 BootOptionSelected = 0;\r
466 }\r
467 }\r
468\r
469 // Start the selected entry\r
470 if (BootOptionSelected > BootOptionCount) {\r
471 // Start the hardcoded entry\r
472 Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);\r
473 } else {\r
474 // Find the selected entry from the Boot#### list\r
475 Index = 1;\r
476 for (Entry = GetFirstNode (&BootOptionsList);\r
477 !IsNull (&BootOptionsList,Entry);\r
478 Entry = GetNextNode (&BootOptionsList,Entry)\r
479 )\r
480 {\r
481 if (Index == BootOptionSelected) {\r
482 BootOption = LOAD_OPTION_FROM_LINK(Entry);\r
483 break;\r
484 }\r
485 Index++;\r
486 }\r
487\r
488 Status = BootOptionStart (BootOption);\r
489 }\r
490 }\r
491\r
492 return Status;\r
493}\r