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