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