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