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