]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Library/BootMaintenanceManagerUiLib/BootOption.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Library / BootMaintenanceManagerUiLib / BootOption.c
... / ...
CommitLineData
1/** @file\r
2 Provide boot option support for Application "BootMaint"\r
3\r
4 Include file system navigation, system handle selection\r
5\r
6 Boot option manipulation\r
7\r
8Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
9SPDX-License-Identifier: BSD-2-Clause-Patent\r
10\r
11**/\r
12\r
13#include "BootMaintenanceManager.h"\r
14\r
15///\r
16/// Define the maximum characters that will be accepted.\r
17///\r
18#define MAX_CHAR 480\r
19\r
20/**\r
21\r
22 Check whether a reset is needed, if reset is needed, Popup a menu to notice user.\r
23\r
24**/\r
25VOID\r
26BmmSetupResetReminder (\r
27 VOID\r
28 )\r
29{\r
30 EFI_INPUT_KEY Key;\r
31 CHAR16 *StringBuffer1;\r
32 CHAR16 *StringBuffer2;\r
33 EFI_STATUS Status;\r
34 EDKII_FORM_BROWSER_EXTENSION2_PROTOCOL *FormBrowserEx2;\r
35\r
36 //\r
37 // Use BrowserEx2 protocol to check whether reset is required.\r
38 //\r
39 Status = gBS->LocateProtocol (&gEdkiiFormBrowserEx2ProtocolGuid, NULL, (VOID **)&FormBrowserEx2);\r
40\r
41 //\r
42 // check any reset required change is applied? if yes, reset system\r
43 //\r
44 if (!EFI_ERROR (Status) && FormBrowserEx2->IsResetRequired ()) {\r
45 StringBuffer1 = AllocateZeroPool (MAX_CHAR * sizeof (CHAR16));\r
46 ASSERT (StringBuffer1 != NULL);\r
47 StringBuffer2 = AllocateZeroPool (MAX_CHAR * sizeof (CHAR16));\r
48 ASSERT (StringBuffer2 != NULL);\r
49 StrCpyS (StringBuffer1, MAX_CHAR, L"Configuration changed. Reset to apply it Now.");\r
50 StrCpyS (StringBuffer2, MAX_CHAR, L"Press ENTER to reset");\r
51 //\r
52 // Popup a menu to notice user\r
53 //\r
54 do {\r
55 CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);\r
56 } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
57\r
58 FreePool (StringBuffer1);\r
59 FreePool (StringBuffer2);\r
60\r
61 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);\r
62 }\r
63}\r
64\r
65/**\r
66 Create a menu entry by given menu type.\r
67\r
68 @param MenuType The Menu type to be created.\r
69\r
70 @retval NULL If failed to create the menu.\r
71 @return the new menu entry.\r
72\r
73**/\r
74BM_MENU_ENTRY *\r
75BOpt_CreateMenuEntry (\r
76 UINTN MenuType\r
77 )\r
78{\r
79 BM_MENU_ENTRY *MenuEntry;\r
80 UINTN ContextSize;\r
81\r
82 //\r
83 // Get context size according to menu type\r
84 //\r
85 switch (MenuType) {\r
86 case BM_LOAD_CONTEXT_SELECT:\r
87 ContextSize = sizeof (BM_LOAD_CONTEXT);\r
88 break;\r
89\r
90 case BM_FILE_CONTEXT_SELECT:\r
91 ContextSize = sizeof (BM_FILE_CONTEXT);\r
92 break;\r
93\r
94 case BM_CONSOLE_CONTEXT_SELECT:\r
95 ContextSize = sizeof (BM_CONSOLE_CONTEXT);\r
96 break;\r
97\r
98 case BM_TERMINAL_CONTEXT_SELECT:\r
99 ContextSize = sizeof (BM_TERMINAL_CONTEXT);\r
100 break;\r
101\r
102 case BM_HANDLE_CONTEXT_SELECT:\r
103 ContextSize = sizeof (BM_HANDLE_CONTEXT);\r
104 break;\r
105\r
106 default:\r
107 ContextSize = 0;\r
108 break;\r
109 }\r
110\r
111 if (ContextSize == 0) {\r
112 return NULL;\r
113 }\r
114\r
115 //\r
116 // Create new menu entry\r
117 //\r
118 MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));\r
119 if (MenuEntry == NULL) {\r
120 return NULL;\r
121 }\r
122\r
123 MenuEntry->VariableContext = AllocateZeroPool (ContextSize);\r
124 if (MenuEntry->VariableContext == NULL) {\r
125 FreePool (MenuEntry);\r
126 return NULL;\r
127 }\r
128\r
129 MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE;\r
130 MenuEntry->ContextSelection = MenuType;\r
131 return MenuEntry;\r
132}\r
133\r
134/**\r
135 Free up all resource allocated for a BM_MENU_ENTRY.\r
136\r
137 @param MenuEntry A pointer to BM_MENU_ENTRY.\r
138\r
139**/\r
140VOID\r
141BOpt_DestroyMenuEntry (\r
142 BM_MENU_ENTRY *MenuEntry\r
143 )\r
144{\r
145 BM_LOAD_CONTEXT *LoadContext;\r
146 BM_FILE_CONTEXT *FileContext;\r
147 BM_CONSOLE_CONTEXT *ConsoleContext;\r
148 BM_TERMINAL_CONTEXT *TerminalContext;\r
149 BM_HANDLE_CONTEXT *HandleContext;\r
150\r
151 //\r
152 // Select by the type in Menu entry for current context type\r
153 //\r
154 switch (MenuEntry->ContextSelection) {\r
155 case BM_LOAD_CONTEXT_SELECT:\r
156 LoadContext = (BM_LOAD_CONTEXT *)MenuEntry->VariableContext;\r
157 FreePool (LoadContext->FilePathList);\r
158 if (LoadContext->OptionalData != NULL) {\r
159 FreePool (LoadContext->OptionalData);\r
160 }\r
161\r
162 FreePool (LoadContext);\r
163 break;\r
164\r
165 case BM_FILE_CONTEXT_SELECT:\r
166 FileContext = (BM_FILE_CONTEXT *)MenuEntry->VariableContext;\r
167\r
168 if (!FileContext->IsRoot) {\r
169 FreePool (FileContext->DevicePath);\r
170 } else {\r
171 if (FileContext->FHandle != NULL) {\r
172 FileContext->FHandle->Close (FileContext->FHandle);\r
173 }\r
174 }\r
175\r
176 if (FileContext->FileName != NULL) {\r
177 FreePool (FileContext->FileName);\r
178 }\r
179\r
180 if (FileContext->Info != NULL) {\r
181 FreePool (FileContext->Info);\r
182 }\r
183\r
184 FreePool (FileContext);\r
185 break;\r
186\r
187 case BM_CONSOLE_CONTEXT_SELECT:\r
188 ConsoleContext = (BM_CONSOLE_CONTEXT *)MenuEntry->VariableContext;\r
189 FreePool (ConsoleContext->DevicePath);\r
190 FreePool (ConsoleContext);\r
191 break;\r
192\r
193 case BM_TERMINAL_CONTEXT_SELECT:\r
194 TerminalContext = (BM_TERMINAL_CONTEXT *)MenuEntry->VariableContext;\r
195 FreePool (TerminalContext->DevicePath);\r
196 FreePool (TerminalContext);\r
197 break;\r
198\r
199 case BM_HANDLE_CONTEXT_SELECT:\r
200 HandleContext = (BM_HANDLE_CONTEXT *)MenuEntry->VariableContext;\r
201 FreePool (HandleContext);\r
202 break;\r
203\r
204 default:\r
205 break;\r
206 }\r
207\r
208 FreePool (MenuEntry->DisplayString);\r
209 if (MenuEntry->HelpString != NULL) {\r
210 FreePool (MenuEntry->HelpString);\r
211 }\r
212\r
213 FreePool (MenuEntry);\r
214}\r
215\r
216/**\r
217 Get the Menu Entry from the list in Menu Entry List.\r
218\r
219 If MenuNumber is great or equal to the number of Menu\r
220 Entry in the list, then ASSERT.\r
221\r
222 @param MenuOption The Menu Entry List to read the menu entry.\r
223 @param MenuNumber The index of Menu Entry.\r
224\r
225 @return The Menu Entry.\r
226\r
227**/\r
228BM_MENU_ENTRY *\r
229BOpt_GetMenuEntry (\r
230 BM_MENU_OPTION *MenuOption,\r
231 UINTN MenuNumber\r
232 )\r
233{\r
234 BM_MENU_ENTRY *NewMenuEntry;\r
235 UINTN Index;\r
236 LIST_ENTRY *List;\r
237\r
238 ASSERT (MenuNumber < MenuOption->MenuNumber);\r
239\r
240 List = MenuOption->Head.ForwardLink;\r
241 for (Index = 0; Index < MenuNumber; Index++) {\r
242 List = List->ForwardLink;\r
243 }\r
244\r
245 NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);\r
246\r
247 return NewMenuEntry;\r
248}\r
249\r
250/**\r
251 Free resources allocated in Allocate Rountine.\r
252\r
253 @param FreeMenu Menu to be freed\r
254**/\r
255VOID\r
256BOpt_FreeMenu (\r
257 BM_MENU_OPTION *FreeMenu\r
258 )\r
259{\r
260 BM_MENU_ENTRY *MenuEntry;\r
261\r
262 while (!IsListEmpty (&FreeMenu->Head)) {\r
263 MenuEntry = CR (\r
264 FreeMenu->Head.ForwardLink,\r
265 BM_MENU_ENTRY,\r
266 Link,\r
267 BM_MENU_ENTRY_SIGNATURE\r
268 );\r
269 RemoveEntryList (&MenuEntry->Link);\r
270 BOpt_DestroyMenuEntry (MenuEntry);\r
271 }\r
272\r
273 FreeMenu->MenuNumber = 0;\r
274}\r
275\r
276/**\r
277\r
278 Build the BootOptionMenu according to BootOrder Variable.\r
279 This Routine will access the Boot#### to get EFI_LOAD_OPTION.\r
280\r
281 @param CallbackData The BMM context data.\r
282\r
283 @return EFI_NOT_FOUND Fail to find "BootOrder" variable.\r
284 @return EFI_SUCESS Success build boot option menu.\r
285\r
286**/\r
287EFI_STATUS\r
288BOpt_GetBootOptions (\r
289 IN BMM_CALLBACK_DATA *CallbackData\r
290 )\r
291{\r
292 UINTN Index;\r
293 UINT16 BootString[10];\r
294 UINT8 *LoadOptionFromVar;\r
295 UINTN BootOptionSize;\r
296 BOOLEAN BootNextFlag;\r
297 UINT16 *BootOrderList;\r
298 UINTN BootOrderListSize;\r
299 UINT16 *BootNext;\r
300 UINTN BootNextSize;\r
301 BM_MENU_ENTRY *NewMenuEntry;\r
302 BM_LOAD_CONTEXT *NewLoadContext;\r
303 UINT8 *LoadOptionPtr;\r
304 UINTN StringSize;\r
305 UINTN OptionalDataSize;\r
306 UINT8 *LoadOptionEnd;\r
307 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
308 UINTN MenuCount;\r
309 UINT8 *Ptr;\r
310 EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;\r
311 UINTN BootOptionCount;\r
312\r
313 MenuCount = 0;\r
314 BootOrderListSize = 0;\r
315 BootNextSize = 0;\r
316 BootOrderList = NULL;\r
317 BootNext = NULL;\r
318 LoadOptionFromVar = NULL;\r
319 BOpt_FreeMenu (&BootOptionMenu);\r
320 InitializeListHead (&BootOptionMenu.Head);\r
321\r
322 //\r
323 // Get the BootOrder from the Var\r
324 //\r
325 GetEfiGlobalVariable2 (L"BootOrder", (VOID **)&BootOrderList, &BootOrderListSize);\r
326 if (BootOrderList == NULL) {\r
327 return EFI_NOT_FOUND;\r
328 }\r
329\r
330 //\r
331 // Get the BootNext from the Var\r
332 //\r
333 GetEfiGlobalVariable2 (L"BootNext", (VOID **)&BootNext, &BootNextSize);\r
334 if (BootNext != NULL) {\r
335 if (BootNextSize != sizeof (UINT16)) {\r
336 FreePool (BootNext);\r
337 BootNext = NULL;\r
338 }\r
339 }\r
340\r
341 BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);\r
342 for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {\r
343 //\r
344 // Don't display the hidden/inactive boot option\r
345 //\r
346 if (((BootOption[Index].Attributes & LOAD_OPTION_HIDDEN) != 0) || ((BootOption[Index].Attributes & LOAD_OPTION_ACTIVE) == 0)) {\r
347 continue;\r
348 }\r
349\r
350 UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);\r
351 //\r
352 // Get all loadoptions from the VAR\r
353 //\r
354 GetEfiGlobalVariable2 (BootString, (VOID **)&LoadOptionFromVar, &BootOptionSize);\r
355 if (LoadOptionFromVar == NULL) {\r
356 continue;\r
357 }\r
358\r
359 if (BootNext != NULL) {\r
360 BootNextFlag = (BOOLEAN)(*BootNext == BootOrderList[Index]);\r
361 } else {\r
362 BootNextFlag = FALSE;\r
363 }\r
364\r
365 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
366 ASSERT (NULL != NewMenuEntry);\r
367\r
368 NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;\r
369\r
370 LoadOptionPtr = LoadOptionFromVar;\r
371 LoadOptionEnd = LoadOptionFromVar + BootOptionSize;\r
372\r
373 NewMenuEntry->OptionNumber = BootOrderList[Index];\r
374 NewLoadContext->Deleted = FALSE;\r
375 NewLoadContext->IsBootNext = BootNextFlag;\r
376\r
377 //\r
378 // Is a Legacy Device?\r
379 //\r
380 Ptr = (UINT8 *)LoadOptionFromVar;\r
381\r
382 //\r
383 // Attribute = *(UINT32 *)Ptr;\r
384 //\r
385 Ptr += sizeof (UINT32);\r
386\r
387 //\r
388 // FilePathSize = *(UINT16 *)Ptr;\r
389 //\r
390 Ptr += sizeof (UINT16);\r
391\r
392 //\r
393 // Description = (CHAR16 *)Ptr;\r
394 //\r
395 Ptr += StrSize ((CHAR16 *)Ptr);\r
396\r
397 //\r
398 // Now Ptr point to Device Path\r
399 //\r
400 DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)Ptr;\r
401 if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {\r
402 NewLoadContext->IsLegacy = TRUE;\r
403 } else {\r
404 NewLoadContext->IsLegacy = FALSE;\r
405 }\r
406\r
407 //\r
408 // LoadOption is a pointer type of UINT8\r
409 // for easy use with following LOAD_OPTION\r
410 // embedded in this struct\r
411 //\r
412\r
413 NewLoadContext->Attributes = *(UINT32 *)LoadOptionPtr;\r
414\r
415 LoadOptionPtr += sizeof (UINT32);\r
416\r
417 NewLoadContext->FilePathListLength = *(UINT16 *)LoadOptionPtr;\r
418 LoadOptionPtr += sizeof (UINT16);\r
419\r
420 StringSize = StrSize ((UINT16 *)LoadOptionPtr);\r
421\r
422 NewLoadContext->Description = AllocateZeroPool (StrSize ((UINT16 *)LoadOptionPtr));\r
423 ASSERT (NewLoadContext->Description != NULL);\r
424 StrCpyS (NewLoadContext->Description, StrSize ((UINT16 *)LoadOptionPtr) / sizeof (UINT16), (UINT16 *)LoadOptionPtr);\r
425\r
426 ASSERT (NewLoadContext->Description != NULL);\r
427 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
428 NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);\r
429\r
430 LoadOptionPtr += StringSize;\r
431\r
432 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
433 ASSERT (NewLoadContext->FilePathList != NULL);\r
434 CopyMem (\r
435 NewLoadContext->FilePathList,\r
436 (EFI_DEVICE_PATH_PROTOCOL *)LoadOptionPtr,\r
437 NewLoadContext->FilePathListLength\r
438 );\r
439\r
440 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);\r
441 NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);\r
442\r
443 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
444\r
445 if (LoadOptionPtr < LoadOptionEnd) {\r
446 OptionalDataSize = BootOptionSize -\r
447 sizeof (UINT32) -\r
448 sizeof (UINT16) -\r
449 StringSize -\r
450 NewLoadContext->FilePathListLength;\r
451\r
452 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
453 ASSERT (NewLoadContext->OptionalData != NULL);\r
454 CopyMem (\r
455 NewLoadContext->OptionalData,\r
456 LoadOptionPtr,\r
457 OptionalDataSize\r
458 );\r
459 }\r
460\r
461 InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);\r
462 MenuCount++;\r
463 FreePool (LoadOptionFromVar);\r
464 }\r
465\r
466 EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);\r
467\r
468 if (BootNext != NULL) {\r
469 FreePool (BootNext);\r
470 }\r
471\r
472 if (BootOrderList != NULL) {\r
473 FreePool (BootOrderList);\r
474 }\r
475\r
476 BootOptionMenu.MenuNumber = MenuCount;\r
477 return EFI_SUCCESS;\r
478}\r
479\r
480/**\r
481\r
482 Find drivers that will be added as Driver#### variables from handles\r
483 in current system environment\r
484 All valid handles in the system except those consume SimpleFs, LoadFile\r
485 are stored in DriverMenu for future use.\r
486\r
487 @retval EFI_SUCCESS The function complets successfully.\r
488 @return Other value if failed to build the DriverMenu.\r
489\r
490**/\r
491EFI_STATUS\r
492BOpt_FindDrivers (\r
493 VOID\r
494 )\r
495{\r
496 UINTN NoDevicePathHandles;\r
497 EFI_HANDLE *DevicePathHandle;\r
498 UINTN Index;\r
499 EFI_STATUS Status;\r
500 BM_MENU_ENTRY *NewMenuEntry;\r
501 BM_HANDLE_CONTEXT *NewHandleContext;\r
502 EFI_HANDLE CurHandle;\r
503 UINTN OptionNumber;\r
504 EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;\r
505 EFI_LOAD_FILE_PROTOCOL *LoadFile;\r
506\r
507 SimpleFs = NULL;\r
508 LoadFile = NULL;\r
509\r
510 InitializeListHead (&DriverMenu.Head);\r
511\r
512 //\r
513 // At first, get all handles that support Device Path\r
514 // protocol which is the basic requirement for\r
515 // Driver####\r
516 //\r
517 Status = gBS->LocateHandleBuffer (\r
518 ByProtocol,\r
519 &gEfiDevicePathProtocolGuid,\r
520 NULL,\r
521 &NoDevicePathHandles,\r
522 &DevicePathHandle\r
523 );\r
524 if (EFI_ERROR (Status)) {\r
525 return Status;\r
526 }\r
527\r
528 OptionNumber = 0;\r
529 for (Index = 0; Index < NoDevicePathHandles; Index++) {\r
530 CurHandle = DevicePathHandle[Index];\r
531\r
532 Status = gBS->HandleProtocol (\r
533 CurHandle,\r
534 &gEfiSimpleFileSystemProtocolGuid,\r
535 (VOID **)&SimpleFs\r
536 );\r
537 if (Status == EFI_SUCCESS) {\r
538 continue;\r
539 }\r
540\r
541 Status = gBS->HandleProtocol (\r
542 CurHandle,\r
543 &gEfiLoadFileProtocolGuid,\r
544 (VOID **)&LoadFile\r
545 );\r
546 if (Status == EFI_SUCCESS) {\r
547 continue;\r
548 }\r
549\r
550 NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);\r
551 if (NULL == NewMenuEntry) {\r
552 FreePool (DevicePathHandle);\r
553 return EFI_OUT_OF_RESOURCES;\r
554 }\r
555\r
556 NewHandleContext = (BM_HANDLE_CONTEXT *)NewMenuEntry->VariableContext;\r
557 NewHandleContext->Handle = CurHandle;\r
558 NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);\r
559 NewMenuEntry->DisplayString = UiDevicePathToStr (NewHandleContext->DevicePath);\r
560 NewMenuEntry->DisplayStringToken = HiiSetString (mBmmCallbackInfo->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);\r
561 NewMenuEntry->HelpString = NULL;\r
562 NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;\r
563 NewMenuEntry->OptionNumber = OptionNumber;\r
564 OptionNumber++;\r
565 InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);\r
566 }\r
567\r
568 if (DevicePathHandle != NULL) {\r
569 FreePool (DevicePathHandle);\r
570 }\r
571\r
572 DriverMenu.MenuNumber = OptionNumber;\r
573 return EFI_SUCCESS;\r
574}\r
575\r
576/**\r
577\r
578 Get the Option Number that has not been allocated for use.\r
579\r
580 @param Type The type of Option.\r
581\r
582 @return The available Option Number.\r
583\r
584**/\r
585UINT16\r
586BOpt_GetOptionNumber (\r
587 CHAR16 *Type\r
588 )\r
589{\r
590 UINT16 *OrderList;\r
591 UINTN OrderListSize;\r
592 UINTN Index;\r
593 CHAR16 StrTemp[20];\r
594 UINT16 *OptionBuffer;\r
595 UINT16 OptionNumber;\r
596 UINTN OptionSize;\r
597\r
598 OrderListSize = 0;\r
599 OrderList = NULL;\r
600 OptionNumber = 0;\r
601 Index = 0;\r
602\r
603 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);\r
604\r
605 GetEfiGlobalVariable2 (StrTemp, (VOID **)&OrderList, &OrderListSize);\r
606 for (OptionNumber = 0; ; OptionNumber++) {\r
607 if (OrderList != NULL) {\r
608 for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {\r
609 if (OptionNumber == OrderList[Index]) {\r
610 break;\r
611 }\r
612 }\r
613 }\r
614\r
615 if (Index < OrderListSize / sizeof (UINT16)) {\r
616 //\r
617 // The OptionNumber occurs in the OrderList, continue to use next one\r
618 //\r
619 continue;\r
620 }\r
621\r
622 UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN)OptionNumber);\r
623 DEBUG ((DEBUG_ERROR, "Option = %s\n", StrTemp));\r
624 GetEfiGlobalVariable2 (StrTemp, (VOID **)&OptionBuffer, &OptionSize);\r
625 if (NULL == OptionBuffer) {\r
626 //\r
627 // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it\r
628 //\r
629 break;\r
630 }\r
631 }\r
632\r
633 return OptionNumber;\r
634}\r
635\r
636/**\r
637\r
638 Get the Option Number for Boot#### that does not used.\r
639\r
640 @return The available Option Number.\r
641\r
642**/\r
643UINT16\r
644BOpt_GetBootOptionNumber (\r
645 VOID\r
646 )\r
647{\r
648 return BOpt_GetOptionNumber (L"Boot");\r
649}\r
650\r
651/**\r
652\r
653 Get the Option Number for Driver#### that does not used.\r
654\r
655 @return The unused Option Number.\r
656\r
657**/\r
658UINT16\r
659BOpt_GetDriverOptionNumber (\r
660 VOID\r
661 )\r
662{\r
663 return BOpt_GetOptionNumber (L"Driver");\r
664}\r
665\r
666/**\r
667\r
668 Build up all DriverOptionMenu\r
669\r
670 @param CallbackData The BMM context data.\r
671\r
672 @retval EFI_SUCESS The functin completes successfully.\r
673 @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.\r
674 @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.\r
675\r
676**/\r
677EFI_STATUS\r
678BOpt_GetDriverOptions (\r
679 IN BMM_CALLBACK_DATA *CallbackData\r
680 )\r
681{\r
682 UINTN Index;\r
683 UINT16 DriverString[12];\r
684 UINT8 *LoadOptionFromVar;\r
685 UINTN DriverOptionSize;\r
686\r
687 UINT16 *DriverOrderList;\r
688 UINTN DriverOrderListSize;\r
689 BM_MENU_ENTRY *NewMenuEntry;\r
690 BM_LOAD_CONTEXT *NewLoadContext;\r
691 UINT8 *LoadOptionPtr;\r
692 UINTN StringSize;\r
693 UINTN OptionalDataSize;\r
694 UINT8 *LoadOptionEnd;\r
695\r
696 DriverOrderListSize = 0;\r
697 DriverOrderList = NULL;\r
698 DriverOptionSize = 0;\r
699 LoadOptionFromVar = NULL;\r
700 BOpt_FreeMenu (&DriverOptionMenu);\r
701 InitializeListHead (&DriverOptionMenu.Head);\r
702 //\r
703 // Get the DriverOrder from the Var\r
704 //\r
705 GetEfiGlobalVariable2 (L"DriverOrder", (VOID **)&DriverOrderList, &DriverOrderListSize);\r
706 if (DriverOrderList == NULL) {\r
707 return EFI_NOT_FOUND;\r
708 }\r
709\r
710 for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {\r
711 UnicodeSPrint (\r
712 DriverString,\r
713 sizeof (DriverString),\r
714 L"Driver%04x",\r
715 DriverOrderList[Index]\r
716 );\r
717 //\r
718 // Get all loadoptions from the VAR\r
719 //\r
720 GetEfiGlobalVariable2 (DriverString, (VOID **)&LoadOptionFromVar, &DriverOptionSize);\r
721 if (LoadOptionFromVar == NULL) {\r
722 continue;\r
723 }\r
724\r
725 NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);\r
726 if (NULL == NewMenuEntry) {\r
727 return EFI_OUT_OF_RESOURCES;\r
728 }\r
729\r
730 NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;\r
731 LoadOptionPtr = LoadOptionFromVar;\r
732 LoadOptionEnd = LoadOptionFromVar + DriverOptionSize;\r
733 NewMenuEntry->OptionNumber = DriverOrderList[Index];\r
734 NewLoadContext->Deleted = FALSE;\r
735 NewLoadContext->IsLegacy = FALSE;\r
736\r
737 //\r
738 // LoadOption is a pointer type of UINT8\r
739 // for easy use with following LOAD_OPTION\r
740 // embedded in this struct\r
741 //\r
742\r
743 NewLoadContext->Attributes = *(UINT32 *)LoadOptionPtr;\r
744\r
745 LoadOptionPtr += sizeof (UINT32);\r
746\r
747 NewLoadContext->FilePathListLength = *(UINT16 *)LoadOptionPtr;\r
748 LoadOptionPtr += sizeof (UINT16);\r
749\r
750 StringSize = StrSize ((UINT16 *)LoadOptionPtr);\r
751 NewLoadContext->Description = AllocateZeroPool (StringSize);\r
752 ASSERT (NewLoadContext->Description != NULL);\r
753 CopyMem (\r
754 NewLoadContext->Description,\r
755 (UINT16 *)LoadOptionPtr,\r
756 StringSize\r
757 );\r
758 NewMenuEntry->DisplayString = NewLoadContext->Description;\r
759 NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);\r
760\r
761 LoadOptionPtr += StringSize;\r
762\r
763 NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);\r
764 ASSERT (NewLoadContext->FilePathList != NULL);\r
765 CopyMem (\r
766 NewLoadContext->FilePathList,\r
767 (EFI_DEVICE_PATH_PROTOCOL *)LoadOptionPtr,\r
768 NewLoadContext->FilePathListLength\r
769 );\r
770\r
771 NewMenuEntry->HelpString = UiDevicePathToStr (NewLoadContext->FilePathList);\r
772 NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);\r
773\r
774 LoadOptionPtr += NewLoadContext->FilePathListLength;\r
775\r
776 if (LoadOptionPtr < LoadOptionEnd) {\r
777 OptionalDataSize = DriverOptionSize -\r
778 sizeof (UINT32) -\r
779 sizeof (UINT16) -\r
780 StringSize -\r
781 NewLoadContext->FilePathListLength;\r
782\r
783 NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);\r
784 ASSERT (NewLoadContext->OptionalData != NULL);\r
785 CopyMem (\r
786 NewLoadContext->OptionalData,\r
787 LoadOptionPtr,\r
788 OptionalDataSize\r
789 );\r
790 }\r
791\r
792 InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);\r
793 FreePool (LoadOptionFromVar);\r
794 }\r
795\r
796 if (DriverOrderList != NULL) {\r
797 FreePool (DriverOrderList);\r
798 }\r
799\r
800 DriverOptionMenu.MenuNumber = Index;\r
801 return EFI_SUCCESS;\r
802}\r
803\r
804/**\r
805 Get option number according to Boot#### and BootOrder variable.\r
806 The value is saved as #### + 1.\r
807\r
808 @param CallbackData The BMM context data.\r
809**/\r
810VOID\r
811GetBootOrder (\r
812 IN BMM_CALLBACK_DATA *CallbackData\r
813 )\r
814{\r
815 BMM_FAKE_NV_DATA *BmmConfig;\r
816 UINT16 Index;\r
817 UINT16 OptionOrderIndex;\r
818 UINTN DeviceType;\r
819 BM_MENU_ENTRY *NewMenuEntry;\r
820 BM_LOAD_CONTEXT *NewLoadContext;\r
821\r
822 ASSERT (CallbackData != NULL);\r
823\r
824 DeviceType = (UINTN)-1;\r
825 BmmConfig = &CallbackData->BmmFakeNvData;\r
826 ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));\r
827\r
828 for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&\r
829 (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));\r
830 Index++)\r
831 {\r
832 NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);\r
833 NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;\r
834\r
835 if (NewLoadContext->IsLegacy) {\r
836 if (((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType != DeviceType) {\r
837 DeviceType = ((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType;\r
838 } else {\r
839 //\r
840 // Only show one legacy boot option for the same device type\r
841 // assuming the boot options are grouped by the device type\r
842 //\r
843 continue;\r
844 }\r
845 }\r
846\r
847 BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32)(NewMenuEntry->OptionNumber + 1);\r
848 }\r
849}\r
850\r
851/**\r
852 Get driver option order from globalc DriverOptionMenu.\r
853\r
854 @param CallbackData The BMM context data.\r
855\r
856**/\r
857VOID\r
858GetDriverOrder (\r
859 IN BMM_CALLBACK_DATA *CallbackData\r
860 )\r
861{\r
862 BMM_FAKE_NV_DATA *BmmConfig;\r
863 UINT16 Index;\r
864 UINT16 OptionOrderIndex;\r
865 UINTN DeviceType;\r
866 BM_MENU_ENTRY *NewMenuEntry;\r
867 BM_LOAD_CONTEXT *NewLoadContext;\r
868\r
869 ASSERT (CallbackData != NULL);\r
870\r
871 DeviceType = (UINTN)-1;\r
872 BmmConfig = &CallbackData->BmmFakeNvData;\r
873 ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));\r
874\r
875 for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&\r
876 (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));\r
877 Index++)\r
878 {\r
879 NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);\r
880 NewLoadContext = (BM_LOAD_CONTEXT *)NewMenuEntry->VariableContext;\r
881\r
882 if (NewLoadContext->IsLegacy) {\r
883 if (((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType != DeviceType) {\r
884 DeviceType = ((BBS_BBS_DEVICE_PATH *)NewLoadContext->FilePathList)->DeviceType;\r
885 } else {\r
886 //\r
887 // Only show one legacy boot option for the same device type\r
888 // assuming the boot options are grouped by the device type\r
889 //\r
890 continue;\r
891 }\r
892 }\r
893\r
894 BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32)(NewMenuEntry->OptionNumber + 1);\r
895 }\r
896}\r
897\r
898/**\r
899 Boot the file specified by the input file path info.\r
900\r
901 @param FilePath Point to the file path.\r
902\r
903 @retval TRUE Exit caller function.\r
904 @retval FALSE Not exit caller function.\r
905**/\r
906BOOLEAN\r
907EFIAPI\r
908BootFromFile (\r
909 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
910 )\r
911{\r
912 EFI_BOOT_MANAGER_LOAD_OPTION BootOption;\r
913 CHAR16 *FileName;\r
914\r
915 FileName = NULL;\r
916\r
917 FileName = ExtractFileNameFromDevicePath (FilePath);\r
918 if (FileName != NULL) {\r
919 EfiBootManagerInitializeLoadOption (\r
920 &BootOption,\r
921 0,\r
922 LoadOptionTypeBoot,\r
923 LOAD_OPTION_ACTIVE,\r
924 FileName,\r
925 FilePath,\r
926 NULL,\r
927 0\r
928 );\r
929 //\r
930 // Since current no boot from removable media directly is allowed */\r
931 //\r
932 gST->ConOut->ClearScreen (gST->ConOut);\r
933 //\r
934 // Check whether need to reset system.\r
935 //\r
936 BmmSetupResetReminder ();\r
937\r
938 BmmSetConsoleMode (FALSE);\r
939 EfiBootManagerBoot (&BootOption);\r
940 BmmSetConsoleMode (TRUE);\r
941\r
942 FreePool (FileName);\r
943\r
944 EfiBootManagerFreeLoadOption (&BootOption);\r
945 }\r
946\r
947 return FALSE;\r
948}\r
949\r
950/**\r
951 Display the form base on the selected file.\r
952\r
953 @param FilePath Point to the file path.\r
954 @param FormId The form need to display.\r
955\r
956**/\r
957BOOLEAN\r
958ReSendForm (\r
959 IN EFI_DEVICE_PATH_PROTOCOL *FilePath,\r
960 IN EFI_FORM_ID FormId\r
961 )\r
962{\r
963 gBootMaintenancePrivate.LoadContext->FilePathList = FilePath;\r
964\r
965 UpdateOptionPage (&gBootMaintenancePrivate, FormId, FilePath);\r
966\r
967 gBootMaintenancePrivate.FormBrowser2->SendForm (\r
968 gBootMaintenancePrivate.FormBrowser2,\r
969 &gBootMaintenancePrivate.BmmHiiHandle,\r
970 1,\r
971 &mBootMaintGuid,\r
972 FormId,\r
973 NULL,\r
974 NULL\r
975 );\r
976 return TRUE;\r
977}\r
978\r
979/**\r
980 Create boot option base on the input file path info.\r
981\r
982 @param FilePath Point to the file path.\r
983\r
984 @retval TRUE Exit caller function.\r
985 @retval FALSE Not exit caller function.\r
986**/\r
987BOOLEAN\r
988EFIAPI\r
989CreateBootOptionFromFile (\r
990 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
991 )\r
992{\r
993 return ReSendForm (FilePath, FORM_BOOT_ADD_ID);\r
994}\r
995\r
996/**\r
997 Create driver option base on the input file path info.\r
998\r
999 @param FilePath Point to the file path.\r
1000\r
1001 @retval TRUE Exit caller function.\r
1002 @retval FALSE Not exit caller function.\r
1003\r
1004**/\r
1005BOOLEAN\r
1006EFIAPI\r
1007CreateDriverOptionFromFile (\r
1008 IN EFI_DEVICE_PATH_PROTOCOL *FilePath\r
1009 )\r
1010{\r
1011 return ReSendForm (FilePath, FORM_DRV_ADD_FILE_ID);\r
1012}\r