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