ea46ebbe |
1 | /** @file\r |
2 | *\r |
3 | * Copyright (c) 2011, ARM Limited. All rights reserved.\r |
4 | *\r |
5 | * This program and the accompanying materials\r |
6 | * are licensed and made available under the terms and conditions of the BSD License\r |
7 | * which accompanies this distribution. The full text of the license may be found at\r |
8 | * http://opensource.org/licenses/bsd-license.php\r |
9 | *\r |
10 | * THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r |
11 | * WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r |
12 | *\r |
13 | **/\r |
14 | \r |
15 | #include "BdsInternal.h"\r |
16 | \r |
17 | extern EFI_HANDLE mImageHandle;\r |
18 | extern BDS_LOAD_OPTION_SUPPORT *BdsLoadOptionSupportList;\r |
19 | \r |
20 | EFI_STATUS\r |
21 | BootMenuAddBootOption (\r |
22 | IN LIST_ENTRY *BootOptionsList\r |
23 | )\r |
24 | {\r |
25 | EFI_STATUS Status;\r |
26 | LIST_ENTRY SupportedDeviceList;\r |
27 | UINTN SupportedDeviceCount;\r |
28 | BDS_SUPPORTED_DEVICE* SupportedBootDevice;\r |
29 | LIST_ENTRY* Entry;\r |
30 | UINTN SupportedDeviceSelected;\r |
31 | CHAR8 AsciiBootOption[BOOT_DEVICE_OPTION_MAX];\r |
32 | CHAR8 AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r |
33 | CHAR16 *BootDescription;\r |
34 | UINT32 Attributes;\r |
35 | BDS_LOADER_TYPE BootType;\r |
36 | UINTN Index;\r |
37 | BDS_LOAD_OPTION *BdsLoadOption;\r |
38 | EFI_DEVICE_PATH* DevicePath;\r |
39 | EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;\r |
40 | \r |
e862cd50 |
41 | Attributes = 0;\r |
42 | SupportedBootDevice = NULL;\r |
ea46ebbe |
43 | \r |
44 | //\r |
45 | // List the Boot Devices supported\r |
46 | //\r |
47 | \r |
48 | // Start all the drivers first\r |
49 | BdsConnectAllDrivers ();\r |
50 | \r |
51 | // List the supported devices\r |
52 | Status = BootDeviceListSupportedInit (&SupportedDeviceList);\r |
53 | ASSERT_EFI_ERROR(Status);\r |
54 | \r |
55 | SupportedDeviceCount = 0;\r |
56 | for (Entry = GetFirstNode (&SupportedDeviceList);\r |
57 | !IsNull (&SupportedDeviceList,Entry);\r |
58 | Entry = GetNextNode (&SupportedDeviceList,Entry)\r |
59 | )\r |
60 | {\r |
61 | SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r |
62 | Print(L"[%d] %s\n",SupportedDeviceCount+1,SupportedBootDevice->Description);\r |
63 | \r |
64 | DEBUG_CODE_BEGIN();\r |
65 | CHAR16* DevicePathTxt;\r |
66 | EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r |
67 | \r |
68 | Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r |
69 | ASSERT_EFI_ERROR(Status);\r |
70 | DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(SupportedBootDevice->DevicePathProtocol,TRUE,TRUE);\r |
71 | \r |
72 | Print(L"\t- %s\n",DevicePathTxt);\r |
73 | \r |
74 | FreePool(DevicePathTxt);\r |
75 | DEBUG_CODE_END();\r |
76 | \r |
77 | SupportedDeviceCount++;\r |
78 | }\r |
79 | \r |
80 | if (SupportedDeviceCount == 0) {\r |
81 | Print(L"There is no supported device.\n");\r |
82 | Status = EFI_ABORTED;\r |
83 | goto EXIT;\r |
84 | }\r |
85 | \r |
86 | //\r |
87 | // Select the Boot Device\r |
88 | //\r |
89 | SupportedDeviceSelected = 0;\r |
90 | while (SupportedDeviceSelected == 0) {\r |
91 | Print(L"Select the Boot Device: ");\r |
92 | Status = GetHIInputInteger (&SupportedDeviceSelected);\r |
93 | if (EFI_ERROR(Status)) {\r |
94 | Status = EFI_ABORTED;\r |
95 | goto EXIT;\r |
96 | } else if ((SupportedDeviceSelected == 0) || (SupportedDeviceSelected > SupportedDeviceCount)) {\r |
97 | Print(L"Invalid input (max %d)\n",SupportedDeviceSelected);\r |
98 | SupportedDeviceSelected = 0;\r |
99 | }\r |
100 | }\r |
101 | \r |
102 | //\r |
103 | // Get the Device Path for the selected boot device\r |
104 | //\r |
105 | Index = 1;\r |
106 | for (Entry = GetFirstNode (&SupportedDeviceList);\r |
107 | !IsNull (&SupportedDeviceList,Entry);\r |
108 | Entry = GetNextNode (&SupportedDeviceList,Entry)\r |
109 | )\r |
110 | {\r |
111 | if (Index == SupportedDeviceSelected) {\r |
112 | SupportedBootDevice = SUPPORTED_BOOT_DEVICE_FROM_LINK(Entry);\r |
113 | break;\r |
114 | }\r |
115 | Index++;\r |
116 | }\r |
117 | \r |
118 | // Create the specific device path node\r |
119 | Status = SupportedBootDevice->Support->CreateDevicePathNode (SupportedBootDevice, &DevicePathNode, &BootType, &Attributes);\r |
120 | if (EFI_ERROR(Status)) {\r |
121 | Status = EFI_ABORTED;\r |
122 | goto EXIT;\r |
123 | }\r |
124 | // Append the Device Path node to the select device path\r |
125 | DevicePath = AppendDevicePathNode (SupportedBootDevice->DevicePathProtocol, (CONST EFI_DEVICE_PATH_PROTOCOL *)DevicePathNode);\r |
126 | \r |
127 | Print(L"Arguments to pass to the binary: ");\r |
128 | Status = GetHIInputAscii (AsciiBootOption,BOOT_DEVICE_OPTION_MAX);\r |
129 | if (EFI_ERROR(Status)) {\r |
130 | Status = EFI_ABORTED;\r |
131 | goto FREE_DEVICE_PATH;\r |
132 | }\r |
133 | \r |
134 | Print(L"Description for this new Entry: ");\r |
135 | Status = GetHIInputAscii (AsciiBootDescription,BOOT_DEVICE_DESCRIPTION_MAX);\r |
136 | if (EFI_ERROR(Status)) {\r |
137 | Status = EFI_ABORTED;\r |
138 | goto FREE_DEVICE_PATH;\r |
139 | }\r |
140 | \r |
141 | // Convert Ascii into Unicode\r |
142 | BootDescription = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootDescription) * sizeof(CHAR16));\r |
143 | AsciiStrToUnicodeStr (AsciiBootDescription, BootDescription);\r |
144 | \r |
145 | // Create new entry\r |
146 | Status = BootOptionCreate (Attributes, BootDescription, DevicePath, BootType, AsciiBootOption, &BdsLoadOption);\r |
147 | if (!EFI_ERROR(Status)) {\r |
148 | InsertTailList (BootOptionsList,&BdsLoadOption->Link);\r |
149 | }\r |
150 | \r |
151 | FreePool (BootDescription);\r |
152 | \r |
153 | FREE_DEVICE_PATH:\r |
154 | FreePool (DevicePath);\r |
155 | \r |
156 | EXIT:\r |
157 | BootDeviceListSupportedFree (&SupportedDeviceList);\r |
158 | return Status;\r |
159 | }\r |
160 | \r |
161 | STATIC\r |
162 | EFI_STATUS\r |
163 | BootMenuSelectBootOption (\r |
164 | IN LIST_ENTRY *BootOptionsList,\r |
165 | IN CONST CHAR16* InputStatement,\r |
166 | OUT BDS_LOAD_OPTION **BdsLoadOption\r |
167 | )\r |
168 | {\r |
169 | EFI_STATUS Status;\r |
170 | LIST_ENTRY* Entry;\r |
171 | BDS_LOAD_OPTION *BootOption;\r |
172 | UINTN BootOptionSelected;\r |
173 | UINTN BootOptionCount;\r |
174 | UINTN Index;\r |
175 | \r |
176 | // Display the list of supported boot devices\r |
177 | BootOptionCount = 1;\r |
178 | for (Entry = GetFirstNode (BootOptionsList);\r |
179 | !IsNull (BootOptionsList,Entry);\r |
180 | Entry = GetNextNode (BootOptionsList,Entry)\r |
181 | )\r |
182 | {\r |
183 | BootOption = LOAD_OPTION_FROM_LINK(Entry);\r |
184 | Print(L"[%d] %s\n",BootOptionCount,BootOption->Description);\r |
185 | \r |
186 | DEBUG_CODE_BEGIN();\r |
187 | CHAR16* DevicePathTxt;\r |
188 | EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r |
189 | \r |
190 | Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r |
191 | ASSERT_EFI_ERROR(Status);\r |
192 | DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);\r |
193 | \r |
194 | Print(L"\t- %s\n",DevicePathTxt);\r |
195 | if ((BootOption->OptionalData != NULL) && (BootOption->OptionalData->Arguments != NULL)) {\r |
196 | Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments);\r |
197 | }\r |
198 | \r |
199 | FreePool(DevicePathTxt);\r |
200 | DEBUG_CODE_END();\r |
201 | \r |
202 | BootOptionCount++;\r |
203 | }\r |
204 | \r |
205 | // Get the index of the boot device to delete\r |
206 | BootOptionSelected = 0;\r |
207 | while (BootOptionSelected == 0) {\r |
208 | Print(InputStatement);\r |
209 | Status = GetHIInputInteger (&BootOptionSelected);\r |
210 | if (EFI_ERROR(Status)) {\r |
211 | return Status;\r |
212 | } else if ((BootOptionSelected == 0) || (BootOptionSelected >= BootOptionCount)) {\r |
213 | Print(L"Invalid input (max %d)\n",BootOptionCount);\r |
214 | BootOptionSelected = 0;\r |
215 | }\r |
216 | }\r |
217 | \r |
218 | // Get the structure of the Boot device to delete\r |
219 | Index = 1;\r |
220 | for (Entry = GetFirstNode (BootOptionsList);\r |
221 | !IsNull (BootOptionsList,Entry);\r |
222 | Entry = GetNextNode (BootOptionsList,Entry)\r |
223 | )\r |
224 | {\r |
225 | if (Index == BootOptionSelected) {\r |
226 | *BdsLoadOption = LOAD_OPTION_FROM_LINK(Entry);\r |
227 | break;\r |
228 | }\r |
229 | Index++;\r |
230 | }\r |
231 | \r |
232 | return EFI_SUCCESS;\r |
233 | }\r |
234 | \r |
235 | EFI_STATUS\r |
236 | BootMenuRemoveBootOption (\r |
237 | IN LIST_ENTRY *BootOptionsList\r |
238 | )\r |
239 | {\r |
240 | EFI_STATUS Status;\r |
241 | BDS_LOAD_OPTION *BootOption;\r |
242 | \r |
243 | Status = BootMenuSelectBootOption (BootOptionsList,L"Delete entry: ",&BootOption);\r |
244 | if (EFI_ERROR(Status)) {\r |
245 | return Status;\r |
246 | }\r |
247 | \r |
248 | // Delete the BDS Load option structures\r |
249 | BootOptionDelete (BootOption);\r |
250 | \r |
251 | return EFI_SUCCESS;\r |
252 | }\r |
253 | \r |
254 | EFI_STATUS\r |
255 | BootMenuUpdateBootOption (\r |
256 | IN LIST_ENTRY *BootOptionsList\r |
257 | )\r |
258 | {\r |
259 | EFI_STATUS Status;\r |
260 | BDS_LOAD_OPTION *BootOption;\r |
261 | BDS_LOAD_OPTION_SUPPORT* DeviceSupport;\r |
262 | CHAR8 AsciiBootOption[BOOT_DEVICE_OPTION_MAX];\r |
263 | CHAR8 AsciiBootDescription[BOOT_DEVICE_DESCRIPTION_MAX];\r |
264 | CHAR16 *BootDescription;\r |
265 | EFI_DEVICE_PATH* DevicePath;\r |
266 | UINT32 Attributes;\r |
267 | BDS_LOADER_TYPE BootType;\r |
268 | \r |
269 | Status = BootMenuSelectBootOption (BootOptionsList,L"Update entry: ",&BootOption);\r |
270 | if (EFI_ERROR(Status)) {\r |
271 | return Status;\r |
272 | }\r |
273 | \r |
274 | // Get the device support for this Boot Option\r |
275 | Status = BootDeviceGetDeviceSupport (BootOption,&DeviceSupport);\r |
276 | if (EFI_ERROR(Status)) {\r |
277 | Print(L"Impossible to retrieve the supported device for the update\n");\r |
278 | return EFI_UNSUPPORTED;\r |
279 | }\r |
280 | \r |
281 | Status = DeviceSupport->UpdateDevicePathNode (BootOption,&DevicePath,&BootType,&Attributes);\r |
282 | if (EFI_ERROR(Status)) {\r |
283 | Status = EFI_ABORTED;\r |
284 | goto EXIT;\r |
285 | }\r |
286 | \r |
287 | Print(L"Arguments to pass to the binary: ");\r |
288 | if (BootOption->OptionalData) {\r |
289 | AsciiStrnCpy(AsciiBootOption,BootOption->OptionalData->Arguments,BOOT_DEVICE_FILEPATH_MAX);\r |
290 | } else {\r |
291 | AsciiBootOption[0] = '\0';\r |
292 | }\r |
293 | Status = EditHIInputAscii (AsciiBootOption,BOOT_DEVICE_OPTION_MAX);\r |
294 | if (EFI_ERROR(Status)) {\r |
295 | Status = EFI_ABORTED;\r |
296 | goto FREE_DEVICE_PATH;\r |
297 | }\r |
298 | \r |
299 | Print(L"Description for this new Entry: ");\r |
300 | UnicodeStrToAsciiStr (BootOption->Description,AsciiBootDescription);\r |
301 | Status = EditHIInputAscii (AsciiBootDescription,BOOT_DEVICE_DESCRIPTION_MAX);\r |
302 | if (EFI_ERROR(Status)) {\r |
303 | Status = EFI_ABORTED;\r |
304 | goto FREE_DEVICE_PATH;\r |
305 | }\r |
306 | \r |
307 | // Convert Ascii into Unicode\r |
308 | BootDescription = (CHAR16*)AllocatePool(AsciiStrSize(AsciiBootDescription) * sizeof(CHAR16));\r |
309 | AsciiStrToUnicodeStr (AsciiBootDescription, BootDescription);\r |
310 | \r |
311 | // Update the entry\r |
312 | Status = BootOptionUpdate (BootOption, Attributes, BootDescription, DevicePath, BootType, AsciiBootOption);\r |
313 | \r |
314 | FreePool (BootDescription);\r |
315 | \r |
316 | FREE_DEVICE_PATH:\r |
317 | FreePool (DevicePath);\r |
318 | \r |
319 | EXIT:\r |
326d1df9 |
320 | if (Status == EFI_ABORTED) {\r |
321 | Print(L"\n");\r |
322 | }\r |
ea46ebbe |
323 | return Status;\r |
324 | }\r |
325 | \r |
326 | struct BOOT_MANAGER_ENTRY {\r |
327 | CONST CHAR16* Description;\r |
328 | EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r |
329 | } BootManagerEntries[] = {\r |
330 | { L"Add Boot Device Entry", BootMenuAddBootOption },\r |
331 | { L"Update Boot Device Entry", BootMenuUpdateBootOption },\r |
332 | { L"Remove Boot Device Entry", BootMenuRemoveBootOption },\r |
333 | };\r |
334 | \r |
335 | EFI_STATUS\r |
336 | BootMenuManager (\r |
337 | IN LIST_ENTRY *BootOptionsList\r |
338 | )\r |
339 | {\r |
340 | UINTN Index;\r |
341 | UINTN OptionSelected;\r |
342 | UINTN BootManagerEntryCount;\r |
343 | EFI_STATUS Status;\r |
344 | \r |
345 | BootManagerEntryCount = sizeof(BootManagerEntries) / sizeof(struct BOOT_MANAGER_ENTRY);\r |
346 | \r |
347 | while (TRUE) {\r |
348 | // Display Boot Manager menu\r |
349 | for (Index = 0; Index < BootManagerEntryCount; Index++) {\r |
350 | Print(L"[%d] %s\n",Index+1,BootManagerEntries[Index]);\r |
351 | }\r |
352 | Print(L"[%d] Return to main menu\n",Index+1);\r |
353 | \r |
354 | // Select which entry to call\r |
355 | Print(L"Choice: ");\r |
356 | Status = GetHIInputInteger (&OptionSelected);\r |
357 | if (EFI_ERROR(Status) || (OptionSelected == (BootManagerEntryCount+1))) {\r |
326d1df9 |
358 | if (EFI_ERROR(Status)) {\r |
359 | Print(L"\n");\r |
360 | }\r |
ea46ebbe |
361 | return EFI_SUCCESS;\r |
362 | } else if ((OptionSelected > 0) && (OptionSelected <= BootManagerEntryCount)) {\r |
363 | Status = BootManagerEntries[OptionSelected-1].Callback (BootOptionsList);\r |
364 | }\r |
365 | }\r |
366 | \r |
367 | return EFI_SUCCESS;\r |
368 | }\r |
369 | \r |
370 | EFI_STATUS\r |
371 | BootEBL (\r |
372 | IN LIST_ENTRY *BootOptionsList\r |
373 | )\r |
374 | {\r |
375 | EFI_STATUS Status;\r |
376 | \r |
377 | // Start EFI Shell\r |
378 | Status = BdsLoadApplication(mImageHandle, L"Ebl");\r |
379 | if (Status == EFI_NOT_FOUND) {\r |
380 | Print (L"Error: EFI Application not found.\n");\r |
381 | } else if (EFI_ERROR(Status)) {\r |
382 | Print (L"Error: Status Code: 0x%X\n",(UINT32)Status);\r |
383 | }\r |
384 | \r |
385 | return Status;\r |
386 | }\r |
387 | \r |
388 | struct BOOT_MAIN_ENTRY {\r |
389 | CONST CHAR16* Description;\r |
390 | EFI_STATUS (*Callback) (IN LIST_ENTRY *BootOptionsList);\r |
391 | } BootMainEntries[] = {\r |
392 | { L"EBL", BootEBL },\r |
393 | { L"Boot Manager", BootMenuManager },\r |
394 | };\r |
395 | \r |
396 | \r |
397 | EFI_STATUS\r |
398 | BootMenuMain (\r |
399 | VOID\r |
400 | )\r |
401 | {\r |
402 | LIST_ENTRY BootOptionsList;\r |
403 | UINTN OptionCount;\r |
404 | UINTN BootOptionCount;\r |
405 | EFI_STATUS Status;\r |
406 | LIST_ENTRY *Entry;\r |
407 | BDS_LOAD_OPTION *BootOption;\r |
408 | UINTN BootOptionSelected;\r |
409 | UINTN Index;\r |
410 | UINTN BootMainEntryCount;\r |
411 | \r |
e862cd50 |
412 | BootOption = NULL;\r |
ea46ebbe |
413 | BootMainEntryCount = sizeof(BootMainEntries) / sizeof(struct BOOT_MAIN_ENTRY);\r |
a6caee65 |
414 | \r |
ea46ebbe |
415 | // Get Boot#### list\r |
416 | BootOptionList (&BootOptionsList);\r |
417 | \r |
418 | while (TRUE) {\r |
419 | OptionCount = 1;\r |
420 | \r |
421 | // Display the Boot options\r |
422 | for (Entry = GetFirstNode (&BootOptionsList);\r |
423 | !IsNull (&BootOptionsList,Entry);\r |
424 | Entry = GetNextNode (&BootOptionsList,Entry)\r |
425 | )\r |
426 | {\r |
427 | BootOption = LOAD_OPTION_FROM_LINK(Entry);\r |
428 | \r |
429 | Print(L"[%d] %s\n",OptionCount,BootOption->Description);\r |
430 | \r |
431 | DEBUG_CODE_BEGIN();\r |
432 | CHAR16* DevicePathTxt;\r |
433 | EFI_DEVICE_PATH_TO_TEXT_PROTOCOL* DevicePathToTextProtocol;\r |
434 | \r |
435 | Status = gBS->LocateProtocol(&gEfiDevicePathToTextProtocolGuid, NULL, (VOID **)&DevicePathToTextProtocol);\r |
aa95e2f7 |
436 | if (EFI_ERROR(Status)) {\r |
437 | // You must provide an implementation of DevicePathToTextProtocol in your firmware (eg: DevicePathDxe)\r |
438 | DEBUG((EFI_D_ERROR,"Error: Bds requires DevicePathToTextProtocol\n"));\r |
439 | return Status;\r |
440 | }\r |
ea46ebbe |
441 | DevicePathTxt = DevicePathToTextProtocol->ConvertDevicePathToText(BootOption->FilePathList,TRUE,TRUE);\r |
442 | \r |
443 | Print(L"\t- %s\n",DevicePathTxt);\r |
444 | if (BootOption->OptionalData != NULL) {\r |
c60ea9a8 |
445 | Print(L"\t- LoaderType: %d\n", ReadUnaligned32 (&BootOption->OptionalData->LoaderType));\r |
ea46ebbe |
446 | if (BootOption->OptionalData->Arguments != NULL) {\r |
447 | Print(L"\t- Arguments: %a\n",BootOption->OptionalData->Arguments);\r |
448 | }\r |
449 | }\r |
450 | \r |
451 | FreePool(DevicePathTxt);\r |
452 | DEBUG_CODE_END();\r |
453 | \r |
454 | OptionCount++;\r |
455 | }\r |
456 | BootOptionCount = OptionCount-1;\r |
457 | \r |
458 | // Display the hardcoded Boot entries\r |
459 | for (Index = 0; Index < BootMainEntryCount; Index++) {\r |
460 | Print(L"[%d] %s\n",OptionCount,BootMainEntries[Index]);\r |
461 | OptionCount++;\r |
462 | }\r |
463 | \r |
464 | // Request the boot entry from the user\r |
465 | BootOptionSelected = 0;\r |
466 | while (BootOptionSelected == 0) {\r |
467 | Print(L"Start: ");\r |
468 | Status = GetHIInputInteger (&BootOptionSelected);\r |
469 | if (EFI_ERROR(Status) || (BootOptionSelected == 0) || (BootOptionSelected > OptionCount)) {\r |
470 | Print(L"Invalid input (max %d)\n",(OptionCount-1));\r |
471 | BootOptionSelected = 0;\r |
472 | }\r |
473 | }\r |
474 | \r |
475 | // Start the selected entry\r |
476 | if (BootOptionSelected > BootOptionCount) {\r |
477 | // Start the hardcoded entry\r |
478 | Status = BootMainEntries[BootOptionSelected - BootOptionCount - 1].Callback (&BootOptionsList);\r |
479 | } else {\r |
480 | // Find the selected entry from the Boot#### list\r |
481 | Index = 1;\r |
482 | for (Entry = GetFirstNode (&BootOptionsList);\r |
483 | !IsNull (&BootOptionsList,Entry);\r |
484 | Entry = GetNextNode (&BootOptionsList,Entry)\r |
485 | )\r |
486 | {\r |
487 | if (Index == BootOptionSelected) {\r |
488 | BootOption = LOAD_OPTION_FROM_LINK(Entry);\r |
489 | break;\r |
490 | }\r |
491 | Index++;\r |
492 | }\r |
493 | \r |
494 | Status = BootOptionStart (BootOption);\r |
495 | }\r |
496 | }\r |
497 | \r |
498 | return Status;\r |
499 | }\r |