]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BootMenu.c
ArmPlatformPkg/Bds: Replaced 'EBL' by 'UEFI Shell' as the default shell on ARM Platforms
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootMenu.c
1 /** @file
2 *
3 * Copyright (c) 2011-2012, 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",SupportedDeviceCount);
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 ARM_BDS_LOADER_ARGUMENTS* BootArguments;
119 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
120 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];
121 UINT32 Attributes;
122 ARM_BDS_LOADER_TYPE BootType;
123 BDS_LOAD_OPTION_ENTRY *BdsLoadOptionEntry;
124 EFI_DEVICE_PATH *DevicePath;
125 EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
126 EFI_DEVICE_PATH_PROTOCOL *InitrdPathNode;
127 EFI_DEVICE_PATH_PROTOCOL *InitrdPath;
128 UINTN CmdLineSize;
129 BOOLEAN InitrdSupport;
130 UINTN InitrdSize;
131
132 Attributes = 0;
133 SupportedBootDevice = NULL;
134
135 // List the Boot Devices supported
136 Status = SelectBootDevice (&SupportedBootDevice);
137 if (EFI_ERROR(Status)) {
138 Status = EFI_ABORTED;
139 goto EXIT;
140 }
141
142 // Create the specific device path node
143 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application or the kernel", &DevicePathNode, &BootType, &Attributes);
144 if (EFI_ERROR(Status)) {
145 Status = EFI_ABORTED;
146 goto EXIT;
147 }
148 // Append the Device Path node to the select device path
149 DevicePath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNode);
150
151 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
152 Print(L"Add an initrd: ");
153 Status = GetHIInputBoolean (&InitrdSupport);
154 if (EFI_ERROR(Status)) {
155 Status = EFI_ABORTED;
156 goto EXIT;
157 }
158
159 if (InitrdSupport) {
160 // Create the specific device path node
161 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"initrd", &InitrdPathNode, NULL, NULL);
162 if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
163 Status = EFI_ABORTED;
164 goto EXIT;
165 }
166
167 if (InitrdPathNode != NULL) {
168 // Append the Device Path node to the select device path
169 InitrdPath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNode);
170 } else {
171 InitrdPath = NULL;
172 }
173 } else {
174 InitrdPath = NULL;
175 }
176
177 Print(L"Arguments to pass to the binary: ");
178 Status = GetHIInputAscii (CmdLine,BOOT_DEVICE_OPTION_MAX);
179 if (EFI_ERROR(Status)) {
180 Status = EFI_ABORTED;
181 goto FREE_DEVICE_PATH;
182 }
183
184 CmdLineSize = AsciiStrSize (CmdLine);
185 InitrdSize = GetDevicePathSize (InitrdPath);
186
187 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize);
188
189 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;
190 BootArguments->LinuxArguments.InitrdSize = InitrdSize;
191 CopyMem ((VOID*)(&BootArguments->LinuxArguments + 1), CmdLine, CmdLineSize);
192 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);
193 } else {
194 BootArguments = NULL;
195 }
196
197 Print(L"Description for this new Entry: ");
198 Status = GetHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);
199 if (EFI_ERROR(Status)) {
200 Status = EFI_ABORTED;
201 goto FREE_DEVICE_PATH;
202 }
203
204 // Create new entry
205 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY));
206 Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, BootArguments, &BdsLoadOptionEntry->BdsLoadOption);
207 if (!EFI_ERROR(Status)) {
208 InsertTailList (BootOptionsList, &BdsLoadOptionEntry->Link);
209 }
210
211 FREE_DEVICE_PATH:
212 FreePool (DevicePath);
213
214
215 EXIT:
216 if (Status == EFI_ABORTED) {
217 Print(L"\n");
218 }
219 FreePool(SupportedBootDevice);
220 return Status;
221 }
222
223 STATIC
224 EFI_STATUS
225 BootMenuSelectBootOption (
226 IN LIST_ENTRY* BootOptionsList,
227 IN CONST CHAR16* InputStatement,
228 IN BOOLEAN OnlyArmBdsBootEntry,
229 OUT BDS_LOAD_OPTION_ENTRY** BdsLoadOptionEntry
230 )
231 {
232 EFI_STATUS Status;
233 LIST_ENTRY* Entry;
234 BDS_LOAD_OPTION* BdsLoadOption;
235 UINTN BootOptionSelected;
236 UINTN BootOptionCount;
237 UINTN Index;
238
239 // Display the list of supported boot devices
240 BootOptionCount = 0;
241 for (Entry = GetFirstNode (BootOptionsList);
242 !IsNull (BootOptionsList,Entry);
243 Entry = GetNextNode (BootOptionsList, Entry)
244 )
245 {
246 BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);
247
248 if (OnlyArmBdsBootEntry && !IS_ARM_BDS_BOOTENTRY (BdsLoadOption)) {
249 continue;
250 }
251
252 Print (L"[%d] %s\n", (BootOptionCount + 1), BdsLoadOption->Description);
253
254 DEBUG_CODE_BEGIN();
255 CHAR16* DevicePathTxt;
256 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
257 ARM_BDS_LOADER_TYPE LoaderType;
258 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
259
260 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
261 ASSERT_EFI_ERROR(Status);
262 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BdsLoadOption->FilePathList,TRUE,TRUE);
263
264 Print(L"\t- %s\n",DevicePathTxt);
265 OptionalData = BdsLoadOption->OptionalData;
266 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
267 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {
268 Print (L"\t- Arguments: %a\n",&OptionalData->Arguments.LinuxArguments + 1);
269 }
270
271 FreePool(DevicePathTxt);
272 DEBUG_CODE_END();
273
274 BootOptionCount++;
275 }
276
277 // Check if a valid boot option(s) is found
278 if (BootOptionCount == 0) {
279 if (StrCmp (InputStatement, DELETE_BOOT_ENTRY) == 0) {
280 Print (L"Nothing to remove!\n");
281 }else if (StrCmp (InputStatement, UPDATE_BOOT_ENTRY) == 0) {
282 Print (L"Couldn't find valid boot entries\n");
283 } else{
284 Print (L"No supported Boot Entry.\n");
285 }
286
287 return EFI_NOT_FOUND;
288 }
289
290 // Get the index of the boot device to delete
291 BootOptionSelected = 0;
292 while (BootOptionSelected == 0) {
293 Print(InputStatement);
294 Status = GetHIInputInteger (&BootOptionSelected);
295 if (EFI_ERROR(Status)) {
296 return Status;
297 } else if ((BootOptionSelected == 0) || (BootOptionSelected > BootOptionCount)) {
298 Print(L"Invalid input (max %d)\n",BootOptionCount);
299 BootOptionSelected = 0;
300 }
301 }
302
303 // Get the structure of the Boot device to delete
304 Index = 1;
305 for (Entry = GetFirstNode (BootOptionsList);
306 !IsNull (BootOptionsList, Entry);
307 Entry = GetNextNode (BootOptionsList,Entry)
308 )
309 {
310 if (Index == BootOptionSelected) {
311 *BdsLoadOptionEntry = LOAD_OPTION_ENTRY_FROM_LINK(Entry);
312 break;
313 }
314 Index++;
315 }
316
317 return EFI_SUCCESS;
318 }
319
320 EFI_STATUS
321 BootMenuRemoveBootOption (
322 IN LIST_ENTRY *BootOptionsList
323 )
324 {
325 EFI_STATUS Status;
326 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;
327
328 Status = BootMenuSelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, FALSE, &BootOptionEntry);
329 if (EFI_ERROR(Status)) {
330 return Status;
331 }
332
333 // If the Boot Option was attached to a list remove it
334 if (!IsListEmpty (&BootOptionEntry->Link)) {
335 // Remove the entry from the list
336 RemoveEntryList (&BootOptionEntry->Link);
337 }
338
339 // Delete the BDS Load option structures
340 BootOptionDelete (BootOptionEntry->BdsLoadOption);
341
342 return EFI_SUCCESS;
343 }
344
345 EFI_STATUS
346 BootMenuUpdateBootOption (
347 IN LIST_ENTRY *BootOptionsList
348 )
349 {
350 EFI_STATUS Status;
351 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;
352 BDS_LOAD_OPTION *BootOption;
353 BDS_LOAD_OPTION_SUPPORT* DeviceSupport;
354 ARM_BDS_LOADER_ARGUMENTS* BootArguments;
355 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
356 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];
357 EFI_DEVICE_PATH *DevicePath;
358 EFI_DEVICE_PATH *TempInitrdPath;
359 ARM_BDS_LOADER_TYPE BootType;
360 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
361 ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;
362 EFI_DEVICE_PATH *InitrdPathNode;
363 EFI_DEVICE_PATH *InitrdPath;
364 UINTN InitrdSize;
365 UINTN CmdLineSize;
366 BOOLEAN InitrdSupport;
367
368 Status = BootMenuSelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, TRUE, &BootOptionEntry);
369 if (EFI_ERROR(Status)) {
370 return Status;
371 }
372 BootOption = BootOptionEntry->BdsLoadOption;
373
374 // Get the device support for this Boot Option
375 Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport);
376 if (EFI_ERROR(Status)) {
377 Print(L"Not possible to retrieve the supported device for the update\n");
378 return EFI_UNSUPPORTED;
379 }
380
381 Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath, NULL, NULL);
382 if (EFI_ERROR(Status)) {
383 Status = EFI_ABORTED;
384 goto EXIT;
385 }
386
387 OptionalData = BootOption->OptionalData;
388 BootType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((UINT32 *)(&OptionalData->Header.LoaderType));
389
390 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
391 LinuxArguments = &OptionalData->Arguments.LinuxArguments;
392
393 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
394
395 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
396 if (InitrdSize > 0) {
397 Print(L"Keep the initrd: ");
398 } else {
399 Print(L"Add an initrd: ");
400 }
401 Status = GetHIInputBoolean (&InitrdSupport);
402 if (EFI_ERROR(Status)) {
403 Status = EFI_ABORTED;
404 goto EXIT;
405 }
406
407 if (InitrdSupport) {
408 if (InitrdSize > 0) {
409 // Case we update the initrd device path
410 Status = DeviceSupport->UpdateDevicePathNode ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize), L"initrd", &InitrdPath, NULL, NULL);
411 if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
412 Status = EFI_ABORTED;
413 goto EXIT;
414 }
415 InitrdSize = GetDevicePathSize (InitrdPath);
416 } else {
417 // Case we create the initrd device path
418
419 Status = DeviceSupport->CreateDevicePathNode (L"initrd", &InitrdPathNode, NULL, NULL);
420 if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
421 Status = EFI_ABORTED;
422 goto EXIT;
423 }
424
425 if (InitrdPathNode != NULL) {
426 // Duplicate Linux kernel Device Path
427 TempInitrdPath = DuplicateDevicePath (BootOption->FilePathList);
428 // Replace Linux kernel Node by EndNode
429 SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath));
430 // Append the Device Path node to the select device path
431 InitrdPath = AppendDevicePathNode (TempInitrdPath, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNode);
432 FreePool (TempInitrdPath);
433 InitrdSize = GetDevicePathSize (InitrdPath);
434 } else {
435 InitrdPath = NULL;
436 }
437 }
438 } else {
439 InitrdSize = 0;
440 }
441
442 Print(L"Arguments to pass to the binary: ");
443 if (CmdLineSize > 0) {
444 AsciiStrnCpy(CmdLine, (CONST CHAR8*)(LinuxArguments + 1), CmdLineSize);
445 } else {
446 CmdLine[0] = '\0';
447 }
448 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);
449 if (EFI_ERROR(Status)) {
450 Status = EFI_ABORTED;
451 goto FREE_DEVICE_PATH;
452 }
453
454 CmdLineSize = AsciiStrSize (CmdLine);
455
456 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool(sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize);
457 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;
458 BootArguments->LinuxArguments.InitrdSize = InitrdSize;
459 CopyMem (&BootArguments->LinuxArguments + 1, CmdLine, CmdLineSize);
460 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);
461 } else {
462 BootArguments = NULL;
463 }
464
465 Print(L"Description for this new Entry: ");
466 StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX);
467 Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);
468 if (EFI_ERROR(Status)) {
469 Status = EFI_ABORTED;
470 goto FREE_DEVICE_PATH;
471 }
472
473 // Update the entry
474 Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, BootArguments);
475
476 FREE_DEVICE_PATH:
477 FreePool (DevicePath);
478
479 EXIT:
480 if (Status == EFI_ABORTED) {
481 Print(L"\n");
482 }
483 return Status;
484 }
485
486 EFI_STATUS
487 UpdateFdtPath (
488 IN LIST_ENTRY *BootOptionsList
489 )
490 {
491 EFI_STATUS Status;
492 UINTN FdtDevicePathSize;
493 BDS_SUPPORTED_DEVICE *SupportedBootDevice;
494 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePathNode;
495 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePath;
496
497 Status = SelectBootDevice (&SupportedBootDevice);
498 if (EFI_ERROR(Status)) {
499 Status = EFI_ABORTED;
500 goto EXIT;
501 }
502
503 // Create the specific device path node
504 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNode, NULL, NULL);
505 if (EFI_ERROR(Status)) {
506 Status = EFI_ABORTED;
507 goto EXIT;
508 }
509
510 if (FdtDevicePathNode != NULL) {
511 // Append the Device Path node to the select device path
512 FdtDevicePath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNode);
513 FdtDevicePathSize = GetDevicePathSize (FdtDevicePath);
514 Status = gRT->SetVariable ((CHAR16*)L"Fdt", &gEfiGlobalVariableGuid, (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS ), FdtDevicePathSize, FdtDevicePath);
515 ASSERT_EFI_ERROR(Status);
516 } else {
517 gRT->SetVariable ((CHAR16*)L"Fdt", &gEfiGlobalVariableGuid, (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS ), 0, NULL);
518 ASSERT_EFI_ERROR(Status);
519 }
520
521 EXIT:
522 if (Status == EFI_ABORTED) {
523 Print(L"\n");
524 }
525 FreePool(SupportedBootDevice);
526 return Status;
527 }
528
529 struct BOOT_MANAGER_ENTRY {
530 CONST CHAR16* Description;
531 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
532 } BootManagerEntries[] = {
533 { L"Add Boot Device Entry", BootMenuAddBootOption },
534 { L"Update Boot Device Entry", BootMenuUpdateBootOption },
535 { L"Remove Boot Device Entry", BootMenuRemoveBootOption },
536 { L"Update FDT path", UpdateFdtPath },
537 };
538
539 EFI_STATUS
540 BootMenuManager (
541 IN LIST_ENTRY *BootOptionsList
542 )
543 {
544 UINTN Index;
545 UINTN OptionSelected;
546 UINTN BootManagerEntryCount;
547 EFI_STATUS Status;
548
549 BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);
550
551 while (TRUE) {
552 // Display Boot Manager menu
553 for (Index = 0; Index < BootManagerEntryCount; Index++) {
554 Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);
555 }
556 Print(L"[%d] Return to main menu\n",Index+1);
557
558 // Select which entry to call
559 Print(L"Choice: ");
560 Status = GetHIInputInteger (&OptionSelected);
561 if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {
562 if (EFI_ERROR(Status)) {
563 Print(L"\n");
564 }
565 return EFI_SUCCESS;
566 } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {
567 BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);
568 }
569 }
570 // Should never go here
571 }
572
573 EFI_STATUS
574 BootShell (
575 IN LIST_ENTRY *BootOptionsList
576 )
577 {
578 EFI_STATUS Status;
579
580 // Start EFI Shell
581 Status = BdsLoadApplication (mImageHandle, L"Shell", 0, NULL);
582 if (Status == EFI_NOT_FOUND) {
583 Print (L"Error: EFI Application not found.\n");
584 } else if (EFI_ERROR(Status)) {
585 Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);
586 }
587
588 return Status;
589 }
590
591 struct BOOT_MAIN_ENTRY {
592 CONST CHAR16* Description;
593 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
594 } BootMainEntries[] = {
595 { L"Shell", BootShell },
596 { L"Boot Manager", BootMenuManager },
597 };
598
599
600 EFI_STATUS
601 BootMenuMain (
602 VOID
603 )
604 {
605 LIST_ENTRY BootOptionsList;
606 UINTN OptionCount;
607 UINTN BootOptionCount;
608 EFI_STATUS Status;
609 LIST_ENTRY* Entry;
610 BDS_LOAD_OPTION* BootOption;
611 UINTN BootOptionSelected;
612 UINTN Index;
613 UINTN BootMainEntryCount;
614
615 BootOption = NULL;
616 BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);
617
618 while (TRUE) {
619 // Get Boot#### list
620 BootOptionList (&BootOptionsList);
621
622 OptionCount = 1;
623
624 // Display the Boot options
625 for (Entry = GetFirstNode (&BootOptionsList);
626 !IsNull (&BootOptionsList,Entry);
627 Entry = GetNextNode (&BootOptionsList,Entry)
628 )
629 {
630 BootOption = LOAD_OPTION_FROM_LINK(Entry);
631
632 Print(L"[%d] %s\n", OptionCount, BootOption->Description);
633
634 DEBUG_CODE_BEGIN();
635 CHAR16* DevicePathTxt;
636 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
637 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
638 UINTN CmdLineSize;
639 ARM_BDS_LOADER_TYPE LoaderType;
640
641 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
642 if (EFI_ERROR(Status)) {
643 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
644 DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));
645 return Status;
646 }
647 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE);
648
649 Print(L"\t- %s\n",DevicePathTxt);
650
651 // If it is a supported BootEntry then print its details
652 if (IS_ARM_BDS_BOOTENTRY (BootOption)) {
653 OptionalData = BootOption->OptionalData;
654 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
655 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {
656 if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.InitrdSize) > 0) {
657 CmdLineSize = ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize);
658 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (
659 GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(&OptionalData->Arguments.LinuxArguments + 1) + CmdLineSize)), TRUE, TRUE);
660 Print(L"\t- Initrd: %s\n", DevicePathTxt);
661 }
662 Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1));
663 }
664 Print(L"\t- LoaderType: %d\n", LoaderType);
665 }
666 FreePool(DevicePathTxt);
667 DEBUG_CODE_END();
668
669 OptionCount++;
670 }
671 BootOptionCount = OptionCount-1;
672
673 // Display the hardcoded Boot entries
674 for (Index = 0; Index < BootMainEntryCount; Index++) {
675 Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);
676 OptionCount++;
677 }
678
679 // Request the boot entry from the user
680 BootOptionSelected = 0;
681 while (BootOptionSelected == 0) {
682 Print(L"Start: ");
683 Status = GetHIInputInteger (&BootOptionSelected);
684 if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {
685 Print(L"Invalid input (max %d)\n",(OptionCount-1));
686 BootOptionSelected = 0;
687 }
688 }
689
690 // Start the selected entry
691 if (BootOptionSelected > BootOptionCount) {
692 // Start the hardcoded entry
693 Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);
694 } else {
695 // Find the selected entry from the Boot#### list
696 Index = 1;
697 for (Entry = GetFirstNode (&BootOptionsList);
698 !IsNull (&BootOptionsList,Entry);
699 Entry = GetNextNode (&BootOptionsList,Entry)
700 )
701 {
702 if (Index == BootOptionSelected) {
703 BootOption = LOAD_OPTION_FROM_LINK(Entry);
704 break;
705 }
706 Index++;
707 }
708
709 Status = BootOptionStart (BootOption);
710 }
711 }
712 // Should never go here
713 }