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