]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPlatformPkg/Bds/BootMenu.c
ArmPlatformPkg/Bds: Add a signature in front of the Boot Argument propoer to this Bds
[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",SupportedDeviceSelected);
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 *BdsLoadOption;
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 Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, &BootArguments, &BdsLoadOption);
196 if (!EFI_ERROR(Status)) {
197 InsertTailList (BootOptionsList,&BdsLoadOption->Link);
198 }
199
200 FREE_DEVICE_PATH:
201 FreePool (DevicePath);
202
203
204 EXIT:
205 if (Status == EFI_ABORTED) {
206 Print(L"\n");
207 }
208 FreePool(SupportedBootDevice);
209 return Status;
210 }
211
212 STATIC
213 EFI_STATUS
214 BootMenuSelectBootOption (
215 IN LIST_ENTRY *BootOptionsList,
216 IN CONST CHAR16* InputStatement,
217 OUT BDS_LOAD_OPTION **BdsLoadOption
218 )
219 {
220 EFI_STATUS Status;
221 LIST_ENTRY* Entry;
222 BDS_LOAD_OPTION *BootOption;
223 UINTN BootOptionSelected;
224 UINTN BootOptionCount;
225 UINTN Index;
226
227 // Display the list of supported boot devices
228 BootOptionCount = 1;
229 for (Entry = GetFirstNode (BootOptionsList);
230 !IsNull (BootOptionsList,Entry);
231 Entry = GetNextNode (BootOptionsList,Entry)
232 )
233 {
234 BootOption = LOAD_OPTION_FROM_LINK(Entry);
235 Print(L"[%d] %s\n",BootOptionCount,BootOption->Description);
236
237 DEBUG_CODE_BEGIN();
238 CHAR16* DevicePathTxt;
239 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
240 ARM_BDS_LOADER_TYPE LoaderType;
241
242 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
243 ASSERT_EFI_ERROR(Status);
244 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);
245
246 Print(L"\t- %s\n",DevicePathTxt);
247 OptionalData = BdsLoadOption->OptionalData;
248 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
249 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {
250 Print (L"\t- Arguments: %a\n",&OptionalData->Arguments.LinuxArguments + 1);
251 }
252
253 FreePool(DevicePathTxt);
254 DEBUG_CODE_END();
255
256 BootOptionCount++;
257 }
258
259 // Get the index of the boot device to delete
260 BootOptionSelected = 0;
261 while (BootOptionSelected == 0) {
262 Print(InputStatement);
263 Status = GetHIInputInteger (&BootOptionSelected);
264 if (EFI_ERROR(Status)) {
265 return Status;
266 } else if ((BootOptionSelected == 0) || (BootOptionSelected >= BootOptionCount)) {
267 Print(L"Invalid input (max %d)\n",BootOptionCount-1);
268 BootOptionSelected = 0;
269 }
270 }
271
272 // Get the structure of the Boot device to delete
273 Index = 1;
274 for (Entry = GetFirstNode (BootOptionsList);
275 !IsNull (BootOptionsList,Entry);
276 Entry = GetNextNode (BootOptionsList,Entry)
277 )
278 {
279 if (Index == BootOptionSelected) {
280 *BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);
281 break;
282 }
283 Index++;
284 }
285
286 return EFI_SUCCESS;
287 }
288
289 EFI_STATUS
290 BootMenuRemoveBootOption (
291 IN LIST_ENTRY *BootOptionsList
292 )
293 {
294 EFI_STATUS Status;
295 BDS_LOAD_OPTION *BootOption;
296
297 Status = BootMenuSelectBootOption (BootOptionsList,L"Delete entry: ",&BootOption);
298 if (EFI_ERROR(Status)) {
299 return Status;
300 }
301
302 // Delete the BDS Load option structures
303 BootOptionDelete (BootOption);
304
305 return EFI_SUCCESS;
306 }
307
308 EFI_STATUS
309 BootMenuUpdateBootOption (
310 IN LIST_ENTRY *BootOptionsList
311 )
312 {
313 EFI_STATUS Status;
314 BDS_LOAD_OPTION *BootOption;
315 BDS_LOAD_OPTION_SUPPORT* DeviceSupport;
316 ARM_BDS_LOADER_ARGUMENTS* BootArguments;
317 CHAR16 BootDescription[BOOT_DEVICE_DESCRIPTION_MAX];
318 CHAR8 CmdLine[BOOT_DEVICE_OPTION_MAX];
319 EFI_DEVICE_PATH* DevicePath;
320 ARM_BDS_LOADER_TYPE BootType;
321 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
322 ARM_BDS_LINUX_ARGUMENTS* LinuxArguments;
323 EFI_DEVICE_PATH* InitrdPathList;
324 UINTN InitrdSize;
325 UINTN CmdLineSize;
326
327 Status = BootMenuSelectBootOption (BootOptionsList,L"Update entry: ",&BootOption);
328 if (EFI_ERROR(Status)) {
329 return Status;
330 }
331
332 // Get the device support for this Boot Option
333 Status = BootDeviceGetDeviceSupport (BootOption,&DeviceSupport);
334 if (EFI_ERROR(Status)) {
335 Print(L"Impossible to retrieve the supported device for the update\n");
336 return EFI_UNSUPPORTED;
337 }
338
339 Print(L"File path of the EFI Application or the kernel: ");
340 Status = DeviceSupport->UpdateDevicePathNode (BootOption->FilePathList, &DevicePath, NULL, NULL);
341 if (EFI_ERROR(Status)) {
342 Status = EFI_ABORTED;
343 goto EXIT;
344 }
345
346 OptionalData = BootOption->OptionalData;
347 BootType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((UINT32 *)(&OptionalData->Header.LoaderType));
348
349 // TODO: Allow adding an initrd to a boot entry without one
350 if ((BootType == BDS_LOADER_KERNEL_LINUX_ATAG) || (BootType == BDS_LOADER_KERNEL_LINUX_FDT)) {
351 LinuxArguments = &OptionalData->Arguments.LinuxArguments;
352
353 CmdLineSize = ReadUnaligned16 ((CONST UINT16*)&LinuxArguments->CmdLineSize);
354 InitrdSize = GetUnalignedDevicePathSize ((EFI_DEVICE_PATH*)((LinuxArguments + 1) + CmdLineSize));
355
356 Print(L"File path of the initrd: ");
357 Status = DeviceSupport->UpdateDevicePathNode (
358 (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)(LinuxArguments + 1) + CmdLineSize), &InitrdPathList, NULL, NULL);
359 if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {// EFI_NOT_FOUND is returned on empty input string, but we can boot without an initrd
360 Status = EFI_ABORTED;
361 goto EXIT;
362 }
363
364 Print(L"Arguments to pass to the binary: ");
365 if (CmdLineSize > 0) {
366 AsciiStrnCpy(CmdLine, (CONST CHAR8*)(LinuxArguments + 1), CmdLineSize);
367 } else {
368 CmdLine[0] = '\0';
369 }
370 Status = EditHIInputAscii (CmdLine, BOOT_DEVICE_OPTION_MAX);
371 if (EFI_ERROR(Status)) {
372 Status = EFI_ABORTED;
373 goto FREE_DEVICE_PATH;
374 }
375
376 CmdLineSize = AsciiStrSize (CmdLine);
377 InitrdSize = GetDevicePathSize (InitrdPathList);
378
379 BootArguments = (ARM_BDS_LOADER_ARGUMENTS*)AllocatePool(sizeof(ARM_BDS_LOADER_ARGUMENTS) + CmdLineSize + InitrdSize);
380 BootArguments->LinuxArguments.CmdLineSize = CmdLineSize;
381 BootArguments->LinuxArguments.InitrdSize = InitrdSize;
382 CopyMem (&BootArguments->LinuxArguments + 1, CmdLine, CmdLineSize);
383 CopyMem ((UINTN)(&BootArguments->LinuxArguments + 1) + CmdLine, InitrdPathList, InitrdSize);
384 } else {
385 BootArguments = NULL;
386 }
387
388 Print(L"Description for this new Entry: ");
389 Status = EditHIInputStr (BootDescription, BOOT_DEVICE_DESCRIPTION_MAX);
390 if (EFI_ERROR(Status)) {
391 Status = EFI_ABORTED;
392 goto FREE_DEVICE_PATH;
393 }
394
395 // Update the entry
396 Status = BootOptionUpdate (BootOption, BootOption->Attributes, BootDescription, DevicePath, BootType, BootArguments);
397
398 FREE_DEVICE_PATH:
399 FreePool (DevicePath);
400
401 EXIT:
402 if (Status == EFI_ABORTED) {
403 Print(L"\n");
404 }
405 return Status;
406 }
407
408 struct BOOT_MANAGER_ENTRY {
409 CONST CHAR16* Description;
410 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
411 } BootManagerEntries[] = {
412 { L"Add Boot Device Entry", BootMenuAddBootOption },
413 { L"Update Boot Device Entry", BootMenuUpdateBootOption },
414 { L"Remove Boot Device Entry", BootMenuRemoveBootOption },
415 };
416
417 EFI_STATUS
418 BootMenuManager (
419 IN LIST_ENTRY *BootOptionsList
420 )
421 {
422 UINTN Index;
423 UINTN OptionSelected;
424 UINTN BootManagerEntryCount;
425 EFI_STATUS Status;
426
427 BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);
428
429 while (TRUE) {
430 // Display Boot Manager menu
431 for (Index = 0; Index < BootManagerEntryCount; Index++) {
432 Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);
433 }
434 Print(L"[%d] Return to main menu\n",Index+1);
435
436 // Select which entry to call
437 Print(L"Choice: ");
438 Status = GetHIInputInteger (&OptionSelected);
439 if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {
440 if (EFI_ERROR(Status)) {
441 Print(L"\n");
442 }
443 return EFI_SUCCESS;
444 } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {
445 Status = BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);
446 }
447 }
448
449 return EFI_SUCCESS;
450 }
451
452 EFI_STATUS
453 BootEBL (
454 IN LIST_ENTRY *BootOptionsList
455 )
456 {
457 EFI_STATUS Status;
458
459 // Start EFI Shell
460 Status = BdsLoadApplication(mImageHandle, L"Ebl");
461 if (Status == EFI_NOT_FOUND) {
462 Print (L"Error: EFI Application not found.\n");
463 } else if (EFI_ERROR(Status)) {
464 Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);
465 }
466
467 return Status;
468 }
469
470 struct BOOT_MAIN_ENTRY {
471 CONST CHAR16* Description;
472 EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);
473 } BootMainEntries[] = {
474 { L"EBL", BootEBL },
475 { L"Boot Manager", BootMenuManager },
476 };
477
478
479 EFI_STATUS
480 BootMenuMain (
481 VOID
482 )
483 {
484 LIST_ENTRY BootOptionsList;
485 UINTN OptionCount;
486 UINTN BootOptionCount;
487 EFI_STATUS Status;
488 LIST_ENTRY* Entry;
489 BDS_LOAD_OPTION* BootOption;
490 UINTN BootOptionSelected;
491 UINTN Index;
492 UINTN BootMainEntryCount;
493
494 BootOption = NULL;
495 BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);
496
497 // Get Boot#### list
498 BootOptionList (&BootOptionsList);
499
500 while (TRUE) {
501 OptionCount = 1;
502
503 // Display the Boot options
504 for (Entry = GetFirstNode (&BootOptionsList);
505 !IsNull (&BootOptionsList,Entry);
506 Entry = GetNextNode (&BootOptionsList,Entry)
507 )
508 {
509 BootOption = LOAD_OPTION_FROM_LINK(Entry);
510
511 Print(L"[%d] %s\n",OptionCount,BootOption->Description);
512
513 DEBUG_CODE_BEGIN();
514 CHAR16* DevicePathTxt;
515 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;
516 ARM_BDS_LOADER_OPTIONAL_DATA* OptionalData;
517 UINTN CmdLineSize;
518 ARM_BDS_LOADER_TYPE LoaderType;
519
520 Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);
521 if (EFI_ERROR(Status)) {
522 // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)
523 DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));
524 return Status;
525 }
526 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);
527
528 Print(L"\t- %s\n",DevicePathTxt);
529
530 // If it is a supported BootEntry then print its details
531 if (IS_ARM_BDS_BOOTENTRY (BootOption)) {
532 OptionalData = BootOption->OptionalData;
533 LoaderType = (ARM_BDS_LOADER_TYPE)ReadUnaligned32 ((CONST UINT32*)&OptionalData->Header.LoaderType);
534 if ((LoaderType == BDS_LOADER_KERNEL_LINUX_ATAG) || (LoaderType == BDS_LOADER_KERNEL_LINUX_FDT)) {
535 if (ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.InitrdSize) > 0) {
536 CmdLineSize = ReadUnaligned16 (&OptionalData->Arguments.LinuxArguments.CmdLineSize);
537 DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText (
538 GetAlignedDevicePath ((EFI_DEVICE_PATH*)((UINTN)(&OptionalData->Arguments.LinuxArguments + 1) + CmdLineSize)), TRUE, TRUE);
539 Print(L"\t- Initrd: %s\n", DevicePathTxt);
540 }
541 Print(L"\t- Arguments: %a\n", (&OptionalData->Arguments.LinuxArguments + 1));
542 }
543 Print(L"\t- LoaderType: %d\n", LoaderType);
544 }
545 FreePool(DevicePathTxt);
546 DEBUG_CODE_END();
547
548 OptionCount++;
549 }
550 BootOptionCount = OptionCount-1;
551
552 // Display the hardcoded Boot entries
553 for (Index = 0; Index < BootMainEntryCount; Index++) {
554 Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);
555 OptionCount++;
556 }
557
558 // Request the boot entry from the user
559 BootOptionSelected = 0;
560 while (BootOptionSelected == 0) {
561 Print(L"Start: ");
562 Status = GetHIInputInteger (&BootOptionSelected);
563 if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {
564 Print(L"Invalid input (max %d)\n",(OptionCount-1));
565 BootOptionSelected = 0;
566 }
567 }
568
569 // Start the selected entry
570 if (BootOptionSelected > BootOptionCount) {
571 // Start the hardcoded entry
572 Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);
573 } else {
574 // Find the selected entry from the Boot#### list
575 Index = 1;
576 for (Entry = GetFirstNode (&BootOptionsList);
577 !IsNull (&BootOptionsList,Entry);
578 Entry = GetNextNode (&BootOptionsList,Entry)
579 )
580 {
581 if (Index == BootOptionSelected) {
582 BootOption = LOAD_OPTION_FROM_LINK(Entry);
583 break;
584 }
585 Index++;
586 }
587
588 Status = BootOptionStart (BootOption);
589 }
590 }
591
592 return Status;
593 }