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