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