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