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