]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BootMenu.c
d2dccbc9f274782719efdef8b8e29823967cabdc
[mirror_edk2.git] / ArmPlatformPkg / Bds / BootMenu.c
1 /** @file
2 *
3 * Copyright (c) 2011 - 2015, 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 #include <libfdt.h>
20
21 /**
22 Worker function that displays the list of boot options that is passed in.
23
24 The function loops over the entries of the list of boot options that is passed
25 in. For each entry, the boot option description is displayed on a single line
26 along with the position of the option in the list. In debug mode, the UEFI
27 device path and the arguments of the boot option are displayed as well in
28 subsequent lines.
29
30 @param[in] BootOptionsList List of the boot options
31
32 **/
33 STATIC
34 VOID
35 DisplayBootOptions (
36 IN LIST_ENTRY* BootOptionsList
37 )
38 {
39 EFI_STATUS Status;
40 UINTN BootOptionCount;
41 LIST_ENTRY *Entry;
42 BDS_LOAD_OPTION *BdsLoadOption;
43 BOOLEAN IsUnicode;
44
45 BootOptionCount = 0 ;
46 for (Entry = GetFirstNode (BootOptionsList);
47 !IsNull (BootOptionsList, Entry);
48 Entry = GetNextNode (BootOptionsList, Entry)
49 ) {
50
51 BdsLoadOption = LOAD_OPTION_FROM_LINK (Entry);
52 Print (L"[%d] %s\n", ++BootOptionCount, BdsLoadOption->Description);
53
54 DEBUG_CODE_BEGIN ();
55 CHAR16* DevicePathTxt;
56 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
57 ARM_BDS_LOADER_TYPE LoaderType;
58 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
59
60 Status = gBS->LocateProtocol (
61 &gEfiDevicePathToTextProtocolGuid,
62 NULL,
63 (VOID **)&DevicePathToTextProtocol
64 );
65 ASSERT_EFI_ERROR (Status);
66 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (
67 BdsLoadOption->FilePathList,
68 TRUE,
69 TRUE
70 );
71 Print (L"\t- %s\n", DevicePathTxt);
72
73 OptionalData = BdsLoadOption->OptionalData;
74 if (IS_ARM_BDS_BOOTENTRY (BdsLoadOption)) {
75 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
76 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) ||
77 (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT ) ) {
78 Print (L"\t- Arguments: %a\n", &OptionalData->Arguments.LinuxArguments + 1);
79 }
80 } else if (OptionalData != NULL) {
81 if (IsPrintableString (OptionalData, &IsUnicode)) {
82 if (IsUnicode) {
83 Print (L"\t- Arguments: %s\n", OptionalData);
84 } else {
85 AsciiPrint ("\t- Arguments: %a\n", OptionalData);
86 }
87 }
88 }
89
90 FreePool (DevicePathTxt);
91 DEBUG_CODE_END ();
92 }
93 }
94
95 /**
96 Worker function that asks for a boot option to be selected and returns a
97 pointer to the structure describing the selected boot option.
98
99 @param[in] BootOptionsList List of the boot options
100
101 @retval EFI_SUCCESS Selection succeeded
102 @retval !EFI_SUCCESS Input error or input cancelled
103
104 **/
105 STATIC
106 EFI_STATUS
107 SelectBootOption (
108 IN LIST_ENTRY* BootOptionsList,
109 IN CONST CHAR16* InputStatement,
110 OUT BDS_LOAD_OPTION_ENTRY** BdsLoadOptionEntry
111 )
112 {
113 EFI_STATUS Status;
114 UINTN BootOptionCount;
115 UINT16 *BootOrder;
116 LIST_ENTRY* Entry;
117 UINTN BootOptionSelected;
118 UINTN Index;
119
120 // Get the number of boot options
121 Status = GetGlobalEnvironmentVariable (
122 L"BootOrder", NULL, &BootOptionCount, (VOID**)&BootOrder
123 );
124 if (EFI_ERROR (Status)) {
125 goto ErrorExit;
126 }
127 FreePool (BootOrder);
128 BootOptionCount /= sizeof (UINT16);
129
130 // Check if a valid boot option(s) is found
131 if (BootOptionCount == 0) {
132 if (StrCmp (InputStatement, DELETE_BOOT_ENTRY) == 0) {
133 Print (L"Nothing to remove!\n");
134 } else if (StrCmp (InputStatement, UPDATE_BOOT_ENTRY) == 0) {
135 Print (L"Nothing to update!\n");
136 } else if (StrCmp (InputStatement, MOVE_BOOT_ENTRY) == 0) {
137 Print (L"Nothing to move!\n");
138 } else {
139 Print (L"No supported Boot Entry.\n");
140 }
141 return EFI_NOT_FOUND;
142 }
143
144 // Get the index of the boot device to delete
145 BootOptionSelected = 0;
146 while (BootOptionSelected == 0) {
147 Print (InputStatement);
148 Status = GetHIInputInteger (&BootOptionSelected);
149 if (EFI_ERROR (Status)) {
150 Print (L"\n");
151 goto ErrorExit;
152 } else if ((BootOptionSelected == 0) || (BootOptionSelected > BootOptionCount)) {
153 Print (L"Invalid input (max %d)\n", BootOptionCount);
154 BootOptionSelected = 0;
155 }
156 }
157
158 // Get the structure of the Boot device to delete
159 Index = 1;
160 for (Entry = GetFirstNode (BootOptionsList);
161 !IsNull (BootOptionsList, Entry);
162 Entry = GetNextNode (BootOptionsList,Entry)
163 )
164 {
165 if (Index == BootOptionSelected) {
166 *BdsLoadOptionEntry = LOAD_OPTION_ENTRY_FROM_LINK (Entry);
167 break;
168 }
169 Index++;
170 }
171
172 ErrorExit:
173 return Status;
174 }
175
176 STATIC
177 EFI_STATUS
178 SelectBootDevice (
179 OUT BDS_SUPPORTED_DEVICE** SupportedBootDevice
180 )
181 {
182 EFI_STATUS Status;
183 LIST_ENTRY SupportedDeviceList;
184 UINTN SupportedDeviceCount;
185 LIST_ENTRY* Entry;
186 UINTN SupportedDeviceSelected;
187 UINTN Index;
188
189 //
190 // List the Boot Devices supported
191 //
192
193 // Start all the drivers first
194 BdsConnectAllDrivers ();
195
196 // List the supported devices
197 Status = BootDeviceListSupportedInit (&SupportedDeviceList);
198 ASSERT_EFI_ERROR(Status);
199
200 SupportedDeviceCount = 0;
201 for (Entry = GetFirstNode (&SupportedDeviceList);
202 !IsNull (&SupportedDeviceList,Entry);
203 Entry = GetNextNode (&SupportedDeviceList,Entry)
204 )
205 {
206 *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
207 Print(L"[%d] %s\n",SupportedDeviceCount+1,(*SupportedBootDevice)->Description);
208
209 DEBUG_CODE_BEGIN();
210 CHAR16* DevicePathTxt;
211 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
212
213 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
214 ASSERT_EFI_ERROR(Status);
215 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText ((*SupportedBootDevice)->DevicePathProtocol,TRUE,TRUE);
216
217 Print(L"\t- %s\n",DevicePathTxt);
218
219 FreePool(DevicePathTxt);
220 DEBUG_CODE_END();
221
222 SupportedDeviceCount++;
223 }
224
225 if (SupportedDeviceCount == 0) {
226 Print(L"There is no supported device.\n");
227 Status = EFI_ABORTED;
228 goto EXIT;
229 }
230
231 //
232 // Select the Boot Device
233 //
234 SupportedDeviceSelected = 0;
235 while (SupportedDeviceSelected == 0) {
236 Print(L"Select the Boot Device: ");
237 Status = GetHIInputInteger (&SupportedDeviceSelected);
238 if (EFI_ERROR(Status)) {
239 Status = EFI_ABORTED;
240 goto EXIT;
241 } else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) {
242 Print(L"Invalid input (max %d)\n",SupportedDeviceCount);
243 SupportedDeviceSelected = 0;
244 }
245 }
246
247 //
248 // Get the Device Path for the selected boot device
249 //
250 Index = 1;
251 for (Entry = GetFirstNode (&SupportedDeviceList);
252 !IsNull (&SupportedDeviceList,Entry);
253 Entry = GetNextNode (&SupportedDeviceList,Entry)
254 )
255 {
256 if (Index == SupportedDeviceSelected) {
257 *SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);
258 break;
259 }
260 Index++;
261 }
262
263 EXIT:
264 BootDeviceListSupportedFree (&SupportedDeviceList, *SupportedBootDevice);
265 return Status;
266 }
267
268 EFI_STATUS
269 BootMenuAddBootOption (
270 IN LIST_ENTRY *BootOptionsList
271 )
272 {
273 EFI_STATUS Status;
274 BDS_SUPPORTED_DEVICE* SupportedBootDevice;
275 ARM_BDS_LOADER_ARGUMENTS* BootArguments;
276 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
277 CHAR8 AsciiCmdLine[BOOT_DEVICE_OPTION_MAX];
278 CHAR16 CmdLine[BOOT_DEVICE_OPTION_MAX];
279 UINT32 Attributes;
280 ARM_BDS_LOADER_TYPE BootType;
281 BDS_LOAD_OPTION_ENTRY *BdsLoadOptionEntry;
282 EFI_DEVICE_PATH *DevicePath;
283 EFI_DEVICE_PATH_PROTOCOL *DevicePathNodes;
284 EFI_DEVICE_PATH_PROTOCOL *InitrdPathNodes;
285 EFI_DEVICE_PATH_PROTOCOL *InitrdPath;
286 UINTN CmdLineSize;
287 BOOLEAN InitrdSupport;
288 UINTN InitrdSize;
289 UINT8* OptionalData;
290 UINTN OptionalDataSize;
291
292 Attributes = 0;
293 SupportedBootDevice = NULL;
294
295 // List the Boot Devices supported
296 Status = SelectBootDevice (&SupportedBootDevice);
297 if (EFI_ERROR(Status)) {
298 Status = EFI_ABORTED;
299 goto EXIT;
300 }
301
302 // Create the specific device path node
303 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"EFI Application or the kernel", &DevicePathNodes);
304 if (EFI_ERROR(Status)) {
305 Status = EFI_ABORTED;
306 goto EXIT;
307 }
308 // Append the Device Path to the selected device path
309 DevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNodes);
310 if (DevicePath == NULL) {
311 Status = EFI_OUT_OF_RESOURCES;
312 goto EXIT;
313 }
314
315 if (SupportedBootDevice->Support->RequestBootType) {
316 Status = BootDeviceGetType (DevicePath, &BootType, &Attributes);
317 if (EFI_ERROR(Status)) {
318 Status = EFI_ABORTED;
319 goto EXIT;
320 }
321 } else {
322 BootType = BDS_LOADER_EFI_APPLICATION;
323 }
324
325 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
326 Print(L"Add an initrd: ");
327 Status = GetHIInputBoolean (&InitrdSupport);
328 if (EFI_ERROR(Status)) {
329 Status = EFI_ABORTED;
330 goto EXIT;
331 }
332
333 if (InitrdSupport) {
334 // Create the specific device path node
335 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"initrd", &InitrdPathNodes);
336 if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
337 Status = EFI_ABORTED;
338 goto EXIT;
339 }
340
341 if (InitrdPathNodes != NULL) {
342 // Append the Device Path to the selected device path
343 InitrdPath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes);
344 // Free the InitrdPathNodes created by Support->CreateDevicePathNode()
345 FreePool (InitrdPathNodes);
346
347 if (InitrdPath == NULL) {
348 Status = EFI_OUT_OF_RESOURCES;
349 goto EXIT;
350 }
351 } else {
352 InitrdPath = NULL;
353 }
354 } else {
355 InitrdPath = NULL;
356 }
357
358 Print(L"Arguments to pass to the binary: ");
359 Status = GetHIInputAscii (AsciiCmdLine, BOOT_DEVICE_OPTION_MAX);
360 if (EFI_ERROR(Status)) {
361 Status = EFI_ABORTED;
362 goto FREE_DEVICE_PATH;
363 }
364
365 CmdLineSize = AsciiStrSize (AsciiCmdLine);
366 InitrdSize = GetDevicePathSize (InitrdPath);
367
368 OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize;
369 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize);
370
371 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;
372 BootArguments->LinuxArguments.InitrdSize = InitrdSize;
373 CopyMem ((VOID*)(&BootArguments->LinuxArguments + 1), AsciiCmdLine, CmdLineSize);
374 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);
375
376 OptionalData = (UINT8*)BootArguments;
377 } else {
378 Print (L"Arguments to pass to the EFI Application: ");
379 Status = GetHIInputStr (CmdLine, BOOT_DEVICE_OPTION_MAX);
380 if (EFI_ERROR (Status)) {
381 Status = EFI_ABORTED;
382 goto EXIT;
383 }
384
385 OptionalData = (UINT8*)CmdLine;
386 OptionalDataSize = StrSize (CmdLine);
387 }
388
389 Print(L"Description for this new Entry: ");
390 Status = GetHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);
391 if (EFI_ERROR(Status)) {
392 Status = EFI_ABORTED;
393 goto FREE_DEVICE_PATH;
394 }
395
396 // Create new entry
397 BdsLoadOptionEntry = (BDS_LOAD_OPTION_ENTRY*)AllocatePool (sizeof(BDS_LOAD_OPTION_ENTRY));
398 Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize, &BdsLoadOptionEntry->BdsLoadOption);
399 if (!EFI_ERROR(Status)) {
400 InsertTailList (BootOptionsList, &BdsLoadOptionEntry->Link);
401 }
402
403 FREE_DEVICE_PATH:
404 FreePool (DevicePath);
405
406 EXIT:
407 if (Status == EFI_ABORTED) {
408 Print(L"\n");
409 }
410 FreePool(SupportedBootDevice);
411 return Status;
412 }
413
414 EFI_STATUS
415 BootMenuRemoveBootOption (
416 IN LIST_ENTRY *BootOptionsList
417 )
418 {
419 EFI_STATUS Status;
420 BDS_LOAD_OPTION_ENTRY* BootOptionEntry;
421
422 DisplayBootOptions (BootOptionsList);
423 Status = SelectBootOption (BootOptionsList, DELETE_BOOT_ENTRY, &BootOptionEntry);
424 if (EFI_ERROR (Status)) {
425 return Status;
426 }
427
428 // If the Boot Option was attached to a list remove it
429 if (!IsListEmpty (&BootOptionEntry->Link)) {
430 // Remove the entry from the list
431 RemoveEntryList (&BootOptionEntry->Link);
432 }
433
434 // Delete the BDS Load option structures
435 BootOptionDelete (BootOptionEntry->BdsLoadOption);
436
437 return EFI_SUCCESS;
438 }
439
440 EFI_STATUS
441 BootMenuUpdateBootOption (
442 IN LIST_ENTRY *BootOptionsList
443 )
444 {
445 EFI_STATUS Status;
446 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;
447 BDS_LOAD_OPTION *BootOption;
448 BDS_LOAD_OPTION_SUPPORT* DeviceSupport;
449 ARM_BDS_LOADER_ARGUMENTS* BootArguments;
450 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
451 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];
452 CHAR16 UnicodeCmdLine[BOOT_DEVICE_OPTION_MAX];
453 EFI_DEVICE_PATH *DevicePath;
454 EFI_DEVICE_PATH *TempInitrdPath;
455 ARM_BDS_LOADER_TYPE BootType;
456 ARM_BDS_LOADER_OPTIONAL_DATA* LoaderOptionalData;
457 ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;
458 EFI_DEVICE_PATH *InitrdPathNodes;
459 EFI_DEVICE_PATH *InitrdPath;
460 UINTN InitrdSize;
461 UINTN CmdLineSize;
462 BOOLEAN InitrdSupport;
463 UINT8* OptionalData;
464 UINTN OptionalDataSize;
465 BOOLEAN IsPrintable;
466 BOOLEAN IsUnicode;
467
468 DisplayBootOptions (BootOptionsList);
469 Status = SelectBootOption (BootOptionsList, UPDATE_BOOT_ENTRY, &BootOptionEntry);
470 if (EFI_ERROR (Status)) {
471 return Status;
472 }
473 BootOption = BootOptionEntry->BdsLoadOption;
474
475 // Get the device support for this Boot Option
476 Status = BootDeviceGetDeviceSupport (BootOption->FilePathList, &DeviceSupport);
477 if (EFI_ERROR(Status)) {
478 Print(L"Not possible to retrieve the supported device for the update\n");
479 return EFI_UNSUPPORTED;
480 }
481
482 Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, L"EFI Application or the kernel", &DevicePath);
483 if (EFI_ERROR(Status)) {
484 Status = EFI_ABORTED;
485 goto EXIT;
486 }
487
488 if (DeviceSupport->RequestBootType) {
489 Status = BootDeviceGetType (DevicePath, &BootType, &BootOption->Attributes);
490 if (EFI_ERROR(Status)) {
491 Status = EFI_ABORTED;
492 goto EXIT;
493 }
494 }
495
496 LoaderOptionalData = BootOption->OptionalData;
497 if (LoaderOptionalData != NULL) {
498 BootType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((UINT32 *)(&LoaderOptionalData->Header.LoaderType));
499 } else {
500 BootType = BDS_LOADER_EFI_APPLICATION;
501 }
502
503 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
504 LinuxArguments = &LoaderOptionalData->Arguments.LinuxArguments;
505
506 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
507
508 InitrdSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->InitrdSize);
509 if (InitrdSize > 0) {
510 Print(L"Keep the initrd: ");
511 } else {
512 Print(L"Add an initrd: ");
513 }
514 Status = GetHIInputBoolean (&InitrdSupport);
515 if (EFI_ERROR(Status)) {
516 Status = EFI_ABORTED;
517 goto EXIT;
518 }
519
520 if (InitrdSupport) {
521 if (InitrdSize > 0) {
522 // Case we update the initrd device path
523 Status = DeviceSupport->UpdateDevicePathNode ((EFI_DEVICE_PATH*)((UINTN)(LinuxArguments + 1) + CmdLineSize), L"initrd", &InitrdPath);
524 if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
525 Status = EFI_ABORTED;
526 goto EXIT;
527 }
528 InitrdSize = GetDevicePathSize (InitrdPath);
529 } else {
530 // Case we create the initrd device path
531
532 Status = DeviceSupport->CreateDevicePathNode (L"initrd", &InitrdPathNodes);
533 if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) { // EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
534 Status = EFI_ABORTED;
535 goto EXIT;
536 }
537
538 if (InitrdPathNodes != NULL) {
539 // Duplicate Linux kernel Device Path
540 TempInitrdPath = DuplicateDevicePath (BootOption->FilePathList);
541 // Replace Linux kernel Node by EndNode
542 SetDevicePathEndNode (GetLastDevicePathNode (TempInitrdPath));
543 // Append the Device Path to the selected device path
544 InitrdPath = AppendDevicePath (TempInitrdPath, (CONST EFI_DEVICE_PATH_PROTOCOL *)InitrdPathNodes);
545 FreePool (TempInitrdPath);
546 // Free the InitrdPathNodes created by Support->CreateDevicePathNode()
547 FreePool (InitrdPathNodes);
548 if (InitrdPath == NULL) {
549 Status = EFI_OUT_OF_RESOURCES;
550 goto EXIT;
551 }
552 InitrdSize = GetDevicePathSize (InitrdPath);
553 } else {
554 InitrdPath = NULL;
555 }
556 }
557 } else {
558 InitrdSize = 0;
559 }
560
561 Print(L"Arguments to pass to the binary: ");
562 if (CmdLineSize > 0) {
563 AsciiStrnCpy (CmdLine, (CONST CHAR8*)(LinuxArguments + 1), sizeof (CmdLine));
564 CmdLine[sizeof (CmdLine) - 1] = '\0';
565 } else {
566 CmdLine[0] = '\0';
567 }
568 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);
569 if (EFI_ERROR(Status)) {
570 Status = EFI_ABORTED;
571 goto FREE_DEVICE_PATH;
572 }
573
574 CmdLineSize = AsciiStrSize (CmdLine);
575
576 OptionalDataSize = sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize;
577 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool (OptionalDataSize);
578 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;
579 BootArguments->LinuxArguments.InitrdSize = InitrdSize;
580 CopyMem (&BootArguments->LinuxArguments + 1, CmdLine, CmdLineSize);
581 CopyMem ((VOID*)((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLineSize), InitrdPath, InitrdSize);
582
583 OptionalData = (UINT8*)BootArguments;
584 } else {
585 Print (L"Arguments to pass to the EFI Application: ");
586
587 if (BootOption->OptionalDataSize > 0) {
588 IsPrintable = IsPrintableString (BootOption->OptionalData, &IsUnicode);
589 if (IsPrintable) {
590 //
591 // The size in bytes of the string, final zero included, should
592 // be equal to or at least lower than "BootOption->OptionalDataSize"
593 // and the "IsPrintableString()" has already tested that the length
594 // in number of characters is smaller than BOOT_DEVICE_OPTION_MAX,
595 // final '\0' included. We can thus copy the string for editing
596 // using "CopyMem()". Furthermore, note that in the case of an Unicode
597 // string "StrnCpy()" and "StrCpy()" can not be used to copy the
598 // string because the data pointed to by "BootOption->OptionalData"
599 // is not necessarily 2-byte aligned.
600 //
601 if (IsUnicode) {
602 CopyMem (
603 UnicodeCmdLine, BootOption->OptionalData,
604 MIN (sizeof (UnicodeCmdLine),
605 BootOption->OptionalDataSize)
606 );
607 } else {
608 CopyMem (
609 CmdLine, BootOption->OptionalData,
610 MIN (sizeof (CmdLine),
611 BootOption->OptionalDataSize)
612 );
613 }
614 }
615 } else {
616 UnicodeCmdLine[0] = L'\0';
617 IsPrintable = TRUE;
618 IsUnicode = TRUE;
619 }
620
621 // We do not request arguments for OptionalData that cannot be printed
622 if (IsPrintable) {
623 if (IsUnicode) {
624 Status = EditHIInputStr (UnicodeCmdLine, BOOT_DEVICE_OPTION_MAX);
625 if (EFI_ERROR (Status)) {
626 Status = EFI_ABORTED;
627 goto FREE_DEVICE_PATH;
628 }
629
630 OptionalData = (UINT8*)UnicodeCmdLine;
631 OptionalDataSize = StrSize (UnicodeCmdLine);
632 } else {
633 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);
634 if (EFI_ERROR (Status)) {
635 Status = EFI_ABORTED;
636 goto FREE_DEVICE_PATH;
637 }
638
639 OptionalData = (UINT8*)CmdLine;
640 OptionalDataSize = AsciiStrSize (CmdLine);
641 }
642 } else {
643 // We keep the former OptionalData
644 OptionalData = BootOption->OptionalData;
645 OptionalDataSize = BootOption->OptionalDataSize;
646 }
647 }
648
649 Print(L"Description for this new Entry: ");
650 StrnCpy (BootDescription, BootOption->Description, BOOT_DEVICE_DESCRIPTION_MAX);
651 Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);
652 if (EFI_ERROR(Status)) {
653 Status = EFI_ABORTED;
654 goto FREE_DEVICE_PATH;
655 }
656
657 // Update the entry
658 Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, OptionalData, OptionalDataSize);
659
660 FREE_DEVICE_PATH:
661 FreePool (DevicePath);
662
663 EXIT:
664 if (Status == EFI_ABORTED) {
665 Print(L"\n");
666 }
667 return Status;
668 }
669
670 /**
671 Reorder boot options
672
673 Ask for the boot option to move and then move it when up or down arrows
674 are pressed. This function is called when the user selects the "Reorder Boot
675 Device Entries" entry in the boot manager menu.
676 The order of the boot options in BootOptionList and in the UEFI BootOrder
677 global variable are kept coherent until the user confirm his reordering (ie:
678 he does not exit by pressing escape).
679
680 @param[in] BootOptionsList List of the boot devices constructed in
681 BootMenuMain()
682
683 @retval EFI_SUCCESS No error encountered.
684 @retval !EFI_SUCCESS An error has occured either in the selection of the
685 boot option to move or while interacting with the user.
686
687 **/
688 STATIC
689 EFI_STATUS
690 BootMenuReorderBootOptions (
691 IN LIST_ENTRY *BootOptionsList
692 )
693 {
694 EFI_STATUS Status;
695 BDS_LOAD_OPTION_ENTRY *BootOptionEntry;
696 LIST_ENTRY *SelectedEntry;
697 LIST_ENTRY *PrevEntry;
698 BOOLEAN Move;
699 BOOLEAN Save;
700 BOOLEAN Cancel;
701 UINTN WaitIndex;
702 EFI_INPUT_KEY Key;
703 LIST_ENTRY *SecondEntry;
704 UINTN BootOrderSize;
705 UINT16 *BootOrder;
706 LIST_ENTRY *Entry;
707 UINTN Index;
708
709 DisplayBootOptions (BootOptionsList);
710
711 // Ask to select the boot option to move
712 while (TRUE) {
713 Status = SelectBootOption (BootOptionsList, MOVE_BOOT_ENTRY, &BootOptionEntry);
714 if (EFI_ERROR (Status)) {
715 goto ErrorExit;
716 }
717
718 SelectedEntry = &BootOptionEntry->Link;
719 SecondEntry = NULL;
720 // Note down the previous entry in the list to be able to cancel changes
721 PrevEntry = GetPreviousNode (BootOptionsList, SelectedEntry);
722
723 // Start of interaction
724 while (TRUE) {
725 Print (
726 L"* Use up/down arrows to move the entry '%s'",
727 BootOptionEntry->BdsLoadOption->Description
728 );
729
730 // Wait for a move, save or cancel request
731 Move = FALSE;
732 Save = FALSE;
733 Cancel = FALSE;
734 do {
735 Status = gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &WaitIndex);
736 if (!EFI_ERROR (Status)) {
737 Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
738 }
739 if (EFI_ERROR (Status)) {
740 Print (L"\n");
741 goto ErrorExit;
742 }
743
744 switch (Key.ScanCode) {
745 case SCAN_NULL:
746 Save = (Key.UnicodeChar == CHAR_LINEFEED) ||
747 (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) ||
748 (Key.UnicodeChar == 0x7f);
749 break;
750
751 case SCAN_UP:
752 SecondEntry = GetPreviousNode (BootOptionsList, SelectedEntry);
753 Move = SecondEntry != BootOptionsList;
754 break;
755
756 case SCAN_DOWN:
757 SecondEntry = GetNextNode (BootOptionsList, SelectedEntry);
758 Move = SecondEntry != BootOptionsList;
759 break;
760
761 case SCAN_ESC:
762 Cancel = TRUE;
763 break;
764 }
765 } while ((!Move) && (!Save) && (!Cancel));
766
767 if (Move) {
768 if ((SelectedEntry != NULL) && (SecondEntry != NULL)) {
769 SwapListEntries (SelectedEntry, SecondEntry);
770 }
771 } else {
772 if (Save) {
773 Status = GetGlobalEnvironmentVariable (
774 L"BootOrder", NULL, &BootOrderSize, (VOID**)&BootOrder
775 );
776 BootOrderSize /= sizeof (UINT16);
777
778 if (!EFI_ERROR (Status)) {
779 // The order of the boot options in the 'BootOptionsList' is the
780 // new order that has been just defined by the user. Save this new
781 // order in "BootOrder" UEFI global variable.
782 Entry = GetFirstNode (BootOptionsList);
783 for (Index = 0; Index < BootOrderSize; Index++) {
784 BootOrder[Index] = (LOAD_OPTION_FROM_LINK (Entry))->LoadOptionIndex;
785 Entry = GetNextNode (BootOptionsList, Entry);
786 }
787 Status = gRT->SetVariable (
788 (CHAR16*)L"BootOrder",
789 &gEfiGlobalVariableGuid,
790 EFI_VARIABLE_NON_VOLATILE |
791 EFI_VARIABLE_BOOTSERVICE_ACCESS |
792 EFI_VARIABLE_RUNTIME_ACCESS,
793 BootOrderSize * sizeof (UINT16),
794 BootOrder
795 );
796 FreePool (BootOrder);
797 }
798
799 if (EFI_ERROR (Status)) {
800 Print (L"\nAn error occurred, move not completed!\n");
801 Cancel = TRUE;
802 }
803 }
804
805 if (Cancel) {
806 //
807 // Restore initial position of the selected boot option
808 //
809 RemoveEntryList (SelectedEntry);
810 InsertHeadList (PrevEntry, SelectedEntry);
811 }
812 }
813
814 Print (L"\n");
815 DisplayBootOptions (BootOptionsList);
816 // Saved or cancelled, back to the choice of boot option to move
817 if (!Move) {
818 break;
819 }
820 }
821 }
822
823 ErrorExit:
824 return Status ;
825 }
826
827 EFI_STATUS
828 UpdateFdtPath (
829 IN LIST_ENTRY *BootOptionsList
830 )
831 {
832 EFI_STATUS Status;
833 BDS_SUPPORTED_DEVICE *SupportedBootDevice;
834 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePathNodes;
835 EFI_DEVICE_PATH_PROTOCOL *FdtDevicePath;
836 CHAR16 *FdtTextDevicePath;
837 EFI_PHYSICAL_ADDRESS FdtBlobBase;
838 UINTN FdtBlobSize;
839 UINTN NumPages;
840 EFI_PHYSICAL_ADDRESS FdtConfigurationTableBase;
841
842 SupportedBootDevice = NULL;
843
844 Status = SelectBootDevice (&SupportedBootDevice);
845 if (EFI_ERROR (Status)) {
846 Status = EFI_ABORTED;
847 goto EXIT;
848 }
849
850 // Create the specific device path node
851 Status = SupportedBootDevice->Support->CreateDevicePathNode (L"FDT blob", &FdtDevicePathNodes);
852 if (EFI_ERROR (Status)) {
853 Status = EFI_ABORTED;
854 goto EXIT;
855 }
856
857 if (FdtDevicePathNodes != NULL) {
858 Status = EFI_OUT_OF_RESOURCES;
859
860 FdtDevicePath = AppendDevicePath (SupportedBootDevice->DevicePathProtocol, FdtDevicePathNodes);
861 FreePool (FdtDevicePathNodes);
862 if (FdtDevicePath == NULL) {
863 goto EXIT;
864 }
865
866 FdtTextDevicePath = ConvertDevicePathToText (FdtDevicePath, TRUE, TRUE);
867 if (FdtTextDevicePath == NULL) {
868 goto EXIT;
869 }
870
871 Status = gRT->SetVariable (
872 (CHAR16*)L"Fdt",
873 &gFdtVariableGuid,
874 EFI_VARIABLE_RUNTIME_ACCESS |
875 EFI_VARIABLE_NON_VOLATILE |
876 EFI_VARIABLE_BOOTSERVICE_ACCESS,
877 StrSize (FdtTextDevicePath),
878 FdtTextDevicePath
879 );
880 ASSERT_EFI_ERROR (Status);
881 FreePool (FdtTextDevicePath);
882 } else {
883 Status = gRT->SetVariable (
884 (CHAR16*)L"Fdt",
885 &gFdtVariableGuid,
886 EFI_VARIABLE_RUNTIME_ACCESS |
887 EFI_VARIABLE_NON_VOLATILE |
888 EFI_VARIABLE_BOOTSERVICE_ACCESS,
889 0,
890 NULL
891 );
892 ASSERT_EFI_ERROR (Status);
893 return Status;
894 }
895
896 //
897 // Try to load FDT from the new EFI Device Path
898 //
899
900 //
901 // Load the FDT given its device path.
902 // This operation may fail if the device path is not supported.
903 //
904 FdtBlobBase = 0;
905 NumPages = 0;
906 Status = BdsLoadImage (FdtDevicePath, AllocateAnyPages, &FdtBlobBase, &FdtBlobSize);
907 FreePool (FdtDevicePath);
908
909 if (EFI_ERROR (Status)) {
910 goto EXIT_LOAD_FDT;
911 }
912
913 // Check the FDT header is valid. We only make this check in DEBUG mode in
914 // case the FDT header change on production device and this ASSERT() becomes
915 // not valid.
916 ASSERT (fdt_check_header ((VOID*)(UINTN)FdtBlobBase) == 0);
917
918 //
919 // Ensure the Size of the Device Tree is smaller than the size of the read file
920 //
921 ASSERT ((UINTN)fdt_totalsize ((VOID*)(UINTN)FdtBlobBase) <= FdtBlobSize);
922
923 //
924 // Store the FDT as Runtime Service Data to prevent the Kernel from
925 // overwritting its data.
926 //
927 NumPages = EFI_SIZE_TO_PAGES (FdtBlobSize);
928 Status = gBS->AllocatePages (
929 AllocateAnyPages, EfiRuntimeServicesData,
930 NumPages, &FdtConfigurationTableBase
931 );
932 if (EFI_ERROR (Status)) {
933 goto EXIT_LOAD_FDT;
934 }
935 gBS->CopyMem (
936 (VOID*)(UINTN)FdtConfigurationTableBase,
937 (VOID*)(UINTN)FdtBlobBase,
938 FdtBlobSize
939 );
940
941 //
942 // Install the FDT into the Configuration Table
943 //
944 Status = gBS->InstallConfigurationTable (
945 &gFdtTableGuid,
946 (VOID*)(UINTN)FdtConfigurationTableBase
947 );
948 if (EFI_ERROR (Status)) {
949 gBS->FreePages (FdtConfigurationTableBase, NumPages);
950 }
951
952 EXIT_LOAD_FDT:
953 if (EFI_ERROR (Status)) {
954 Print (L"\nWarning: Did not manage to install the new device tree. Try to restart the platform.\n");
955 }
956
957 if (FdtBlobBase != 0) {
958 gBS->FreePages (FdtBlobBase, NumPages);
959 }
960
961 EXIT:
962 if (Status == EFI_ABORTED) {
963 Print (L"\n");
964 }
965
966 if (SupportedBootDevice != NULL) {
967 FreePool (SupportedBootDevice);
968 }
969
970 return Status;
971 }
972
973 /**
974 Set boot timeout
975
976 Ask for the boot timeout in seconds and if the input succeeds assign the
977 input value to the UEFI global variable "Timeout". This function is called
978 when the user selects the "Set Boot Timeout" of the boot manager menu.
979
980 @param[in] BootOptionsList List of the boot devices, not used here
981
982 @retval EFI_SUCCESS Boot timeout in second retrieved from the standard
983 input and assigned to the UEFI "Timeout" global
984 variable
985 @retval !EFI_SUCCESS Either the input or the setting of the UEFI global
986 variable "Timeout" has failed.
987 **/
988 EFI_STATUS
989 STATIC
990 BootMenuSetBootTimeout (
991 IN LIST_ENTRY *BootOptionsList
992 )
993 {
994 EFI_STATUS Status;
995 UINTN Input;
996 UINT16 Timeout;
997
998 Print (L"Timeout duration (in seconds): ");
999 Status = GetHIInputInteger (&Input);
1000 if (EFI_ERROR (Status)) {
1001 Print (L"\n");
1002 goto ErrorExit;
1003 }
1004
1005 Timeout = Input;
1006 Status = gRT->SetVariable (
1007 (CHAR16*)L"Timeout",
1008 &gEfiGlobalVariableGuid,
1009 EFI_VARIABLE_NON_VOLATILE |
1010 EFI_VARIABLE_BOOTSERVICE_ACCESS |
1011 EFI_VARIABLE_RUNTIME_ACCESS,
1012 sizeof (UINT16),
1013 &Timeout
1014 );
1015 ASSERT_EFI_ERROR (Status);
1016
1017 ErrorExit:
1018 return Status;
1019 }
1020
1021 struct BOOT_MANAGER_ENTRY {
1022 CONST CHAR16* Description;
1023 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
1024 } BootManagerEntries[] = {
1025 { L"Add Boot Device Entry", BootMenuAddBootOption },
1026 { L"Update Boot Device Entry", BootMenuUpdateBootOption },
1027 { L"Remove Boot Device Entry", BootMenuRemoveBootOption },
1028 { L"Reorder Boot Device Entries", BootMenuReorderBootOptions },
1029 { L"Update FDT path", UpdateFdtPath },
1030 { L"Set Boot Timeout", BootMenuSetBootTimeout },
1031 };
1032
1033 EFI_STATUS
1034 BootMenuManager (
1035 IN LIST_ENTRY *BootOptionsList
1036 )
1037 {
1038 UINTN Index;
1039 UINTN OptionSelected;
1040 UINTN BootManagerEntryCount;
1041 EFI_STATUS Status;
1042
1043 BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);
1044
1045 while (TRUE) {
1046 // Display Boot Manager menu
1047 for (Index = 0; Index < BootManagerEntryCount; Index++) {
1048 Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);
1049 }
1050 Print(L"[%d] Return to main menu\n",Index+1);
1051
1052 // Select which entry to call
1053 Print(L"Choice: ");
1054 Status = GetHIInputInteger (&OptionSelected);
1055 if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {
1056 if (EFI_ERROR(Status)) {
1057 Print(L"\n");
1058 }
1059 return EFI_SUCCESS;
1060 } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {
1061 BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);
1062 }
1063 }
1064 // Should never go here
1065 }
1066
1067 EFI_STATUS
1068 BootShell (
1069 IN LIST_ENTRY *BootOptionsList
1070 )
1071 {
1072 EFI_STATUS Status;
1073
1074 // Start EFI Shell
1075 Status = BdsLoadApplication (gImageHandle, L"Shell", 0, NULL);
1076 if (Status == EFI_NOT_FOUND) {
1077 Print (L"Error: EFI Application not found.\n");
1078 } else if (EFI_ERROR(Status)) {
1079 Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);
1080 }
1081
1082 return Status;
1083 }
1084
1085 struct BOOT_MAIN_ENTRY {
1086 CONST CHAR16* Description;
1087 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
1088 } BootMainEntries[] = {
1089 { L"Shell", BootShell },
1090 { L"Boot Manager", BootMenuManager },
1091 };
1092
1093
1094 EFI_STATUS
1095 BootMenuMain (
1096 VOID
1097 )
1098 {
1099 LIST_ENTRY BootOptionsList;
1100 UINTN OptionCount;
1101 UINTN BootOptionCount;
1102 EFI_STATUS Status;
1103 LIST_ENTRY* Entry;
1104 BDS_LOAD_OPTION* BootOption;
1105 UINTN BootOptionSelected;
1106 UINTN Index;
1107 UINTN BootMainEntryCount;
1108 BOOLEAN IsUnicode;
1109
1110 BootOption = NULL;
1111 BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);
1112
1113 while (TRUE) {
1114 // Get Boot#### list
1115 BootOptionList (&BootOptionsList);
1116
1117 OptionCount = 1;
1118
1119 // Display the Boot options
1120 for (Entry = GetFirstNode (&BootOptionsList);
1121 !IsNull (&BootOptionsList,Entry);
1122 Entry = GetNextNode (&BootOptionsList,Entry)
1123 )
1124 {
1125 BootOption = LOAD_OPTION_FROM_LINK(Entry);
1126
1127 Print(L"[%d] %s\n", OptionCount, BootOption->Description);
1128
1129 DEBUG_CODE_BEGIN();
1130 CHAR16* DevicePathTxt;
1131 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
1132 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
1133 UINTN CmdLineSize;
1134 ARM_BDS_LOADER_TYPE LoaderType;
1135
1136 Status = gBS->LocateProtocol (&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
1137 if (EFI_ERROR(Status)) {
1138 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
1139 DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));
1140 return Status;
1141 }
1142 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (BootOption->FilePathList, TRUE, TRUE);
1143
1144 Print(L"\t- %s\n",DevicePathTxt);
1145
1146 // If it is a supported BootEntry then print its details
1147 if (IS_ARM_BDS_BOOTENTRY (BootOption)) {
1148 OptionalData = BootOption->OptionalData;
1149 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
1150 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {
1151 if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.InitrdSize) > 0) {
1152 CmdLineSize = ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize);
1153 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (
1154 GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(&OptionalData->Arguments.LinuxArguments + 1) + CmdLineSize)), TRUE, TRUE);
1155 Print(L"\t- Initrd: %s\n", DevicePathTxt);
1156 }
1157 if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize) > 0) {
1158 Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1));
1159 }
1160 }
1161
1162 switch (LoaderType) {
1163 case BDS_LOADER_EFI_APPLICATION:
1164 Print(L"\t- LoaderType: EFI Application\n");
1165 break;
1166
1167 case BDS_LOADER_KERNEL_LINUX_ATAG:
1168 Print(L"\t- LoaderType: Linux kernel with ATAG support\n");
1169 break;
1170
1171 case BDS_LOADER_KERNEL_LINUX_FDT:
1172 Print(L"\t- LoaderType: Linux kernel with FDT support\n");
1173 break;
1174
1175 default:
1176 Print(L"\t- LoaderType: Not recognized (%d)\n", LoaderType);
1177 }
1178 } else if (BootOption->OptionalData != NULL) {
1179 if (IsPrintableString (BootOption->OptionalData, &IsUnicode)) {
1180 if (IsUnicode) {
1181 Print (L"\t- Arguments: %s\n", BootOption->OptionalData);
1182 } else {
1183 AsciiPrint ("\t- Arguments: %a\n", BootOption->OptionalData);
1184 }
1185 }
1186 }
1187 FreePool(DevicePathTxt);
1188 DEBUG_CODE_END();
1189
1190 OptionCount++;
1191 }
1192 BootOptionCount = OptionCount-1;
1193
1194 // Display the hardcoded Boot entries
1195 for (Index = 0; Index < BootMainEntryCount; Index++) {
1196 Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);
1197 OptionCount++;
1198 }
1199
1200 // Request the boot entry from the user
1201 BootOptionSelected = 0;
1202 while (BootOptionSelected == 0) {
1203 Print(L"Start: ");
1204 Status = GetHIInputInteger (&BootOptionSelected);
1205 if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {
1206 Print(L"Invalid input (max %d)\n",(OptionCount-1));
1207 BootOptionSelected = 0;
1208 }
1209 }
1210
1211 // Start the selected entry
1212 if (BootOptionSelected > BootOptionCount) {
1213 // Start the hardcoded entry
1214 Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);
1215 } else {
1216 // Find the selected entry from the Boot#### list
1217 Index = 1;
1218 for (Entry = GetFirstNode (&BootOptionsList);
1219 !IsNull (&BootOptionsList,Entry);
1220 Entry = GetNextNode (&BootOptionsList,Entry)
1221 )
1222 {
1223 if (Index == BootOptionSelected) {
1224 BootOption = LOAD_OPTION_FROM_LINK(Entry);
1225 break;
1226 }
1227 Index++;
1228 }
1229
1230 Status = BootOptionStart (BootOption);
1231 }
1232 }
1233 // Should never go here
1234 }