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