BootOption.c revision 67013151bafeef044920e457aa275f617b5c6485
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
8Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
9This program and the accompanying materials
10are licensed and made available under the terms and conditions of the BSD License
11which accompanies this distribution.  The full text of the license may be found at
12http://opensource.org/licenses/bsd-license.php
13
14THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15WITHOUT 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**/
35BM_MENU_ENTRY *
36BOpt_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**/
101VOID
102BOpt_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**/
187BM_MENU_ENTRY *
188BOpt_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**/
214VOID
215BOpt_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**/
244EFI_STATUS
245BOpt_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**/
459EFI_STATUS
460BOpt_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**/
554UINT16
555BOpt_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**/
611UINT16
612BOpt_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**/
626UINT16
627BOpt_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**/
645EFI_STATUS
646BOpt_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**/
795VOID
796GetBootOrder (
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**/
840VOID
841GetDriverOrder (
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**/
888BOOLEAN
889BootFromFile (
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**/
930BOOLEAN
931ReSendForm(
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**/
960BOOLEAN
961CreateBootOptionFromFile (
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**/
977BOOLEAN
978CreateDriverOptionFromFile (
979  IN EFI_DEVICE_PATH_PROTOCOL    *FilePath
980  )
981{
982  return ReSendForm(FilePath, FORM_DRV_ADD_FILE_ID);
983}
984
985