1 /** @file
2 Variable operation that will be used by bootmaint
3 
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include "BootMaintenanceManager.h"
10 
11 /**
12   Delete Boot Option that represent a Deleted state in BootOptionMenu.
13 
14   @retval EFI_SUCCESS   If all boot load option EFI Variables corresponding to
15                         BM_LOAD_CONTEXT marked for deletion is deleted.
16   @retval EFI_NOT_FOUND If can not find the boot option want to be deleted.
17   @return Others        If failed to update the "BootOrder" variable after deletion.
18 
19 **/
20 EFI_STATUS
Var_DelBootOption(VOID)21 Var_DelBootOption (
22   VOID
23   )
24 {
25   BM_MENU_ENTRY   *NewMenuEntry;
26   BM_LOAD_CONTEXT *NewLoadContext;
27   EFI_STATUS      Status;
28   UINTN           Index;
29   UINTN           Index2;
30 
31   Index2  = 0;
32   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
33     NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, (Index - Index2));
34     if (NULL == NewMenuEntry) {
35       return EFI_NOT_FOUND;
36     }
37 
38     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
39     if (!NewLoadContext->Deleted) {
40       continue;
41     }
42 
43     Status = EfiBootManagerDeleteLoadOptionVariable (NewMenuEntry->OptionNumber,LoadOptionTypeBoot);
44     if (EFI_ERROR (Status)) {
45      return Status;
46     }
47     Index2++;
48     //
49     // If current Load Option is the same as BootNext,
50     // must delete BootNext in order to make sure
51     // there will be no panic on next boot
52     //
53     if (NewLoadContext->IsBootNext) {
54       EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
55     }
56 
57     RemoveEntryList (&NewMenuEntry->Link);
58     BOpt_DestroyMenuEntry (NewMenuEntry);
59     NewMenuEntry = NULL;
60   }
61 
62   BootOptionMenu.MenuNumber -= Index2;
63 
64   return EFI_SUCCESS;
65 }
66 
67 /**
68   Delete Load Option that represent a Deleted state in DriverOptionMenu.
69 
70   @retval EFI_SUCCESS       Load Option is successfully updated.
71   @retval EFI_NOT_FOUND     Fail to find the driver option want to be deleted.
72   @return Other value than EFI_SUCCESS if failed to update "Driver Order" EFI
73           Variable.
74 
75 **/
76 EFI_STATUS
Var_DelDriverOption(VOID)77 Var_DelDriverOption (
78   VOID
79   )
80 {
81   BM_MENU_ENTRY   *NewMenuEntry;
82   BM_LOAD_CONTEXT *NewLoadContext;
83   EFI_STATUS      Status;
84   UINTN           Index;
85   UINTN           Index2;
86 
87   Index2  = 0;
88   for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
89     NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, (Index - Index2));
90     if (NULL == NewMenuEntry) {
91       return EFI_NOT_FOUND;
92     }
93 
94     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
95     if (!NewLoadContext->Deleted) {
96       continue;
97     }
98     Status = EfiBootManagerDeleteLoadOptionVariable (NewMenuEntry->OptionNumber,LoadOptionTypeDriver);
99     if (EFI_ERROR (Status)) {
100       return Status;
101     }
102 
103     Index2++;
104 
105     RemoveEntryList (&NewMenuEntry->Link);
106     BOpt_DestroyMenuEntry (NewMenuEntry);
107     NewMenuEntry = NULL;
108   }
109 
110   DriverOptionMenu.MenuNumber -= Index2;
111 
112   return EFI_SUCCESS;
113 }
114 
115 /**
116   This function delete and build multi-instance device path for
117   specified type of console device.
118 
119   This function clear the EFI variable defined by ConsoleName and
120   gEfiGlobalVariableGuid. It then build the multi-instance device
121   path by appending the device path of the Console (In/Out/Err) instance
122   in ConsoleMenu. Then it scan all corresponding console device by
123   scanning Terminal (built from device supporting Serial I/O instances)
124   devices in TerminalMenu. At last, it save a EFI variable specifed
125   by ConsoleName and gEfiGlobalVariableGuid.
126 
127   @param ConsoleName     The name for the console device type. They are
128                          usually "ConIn", "ConOut" and "ErrOut".
129   @param ConsoleMenu     The console memu which is a list of console devices.
130   @param UpdatePageId    The flag specifying which type of console device
131                          to be processed.
132 
133   @retval EFI_SUCCESS    The function complete successfully.
134   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
135 
136 **/
137 EFI_STATUS
Var_UpdateConsoleOption(IN UINT16 * ConsoleName,IN BM_MENU_OPTION * ConsoleMenu,IN UINT16 UpdatePageId)138 Var_UpdateConsoleOption (
139   IN UINT16                     *ConsoleName,
140   IN BM_MENU_OPTION             *ConsoleMenu,
141   IN UINT16                     UpdatePageId
142   )
143 {
144   EFI_DEVICE_PATH_PROTOCOL  *ConDevicePath;
145   BM_MENU_ENTRY             *NewMenuEntry;
146   BM_CONSOLE_CONTEXT        *NewConsoleContext;
147   BM_TERMINAL_CONTEXT       *NewTerminalContext;
148   EFI_STATUS                Status;
149   VENDOR_DEVICE_PATH        Vendor;
150   EFI_DEVICE_PATH_PROTOCOL  *TerminalDevicePath;
151   UINTN                     Index;
152 
153   GetEfiGlobalVariable2 (ConsoleName, (VOID**)&ConDevicePath, NULL);
154   if (ConDevicePath != NULL) {
155     EfiLibDeleteVariable (ConsoleName, &gEfiGlobalVariableGuid);
156     FreePool (ConDevicePath);
157     ConDevicePath = NULL;
158   };
159 
160   //
161   // First add all console input device from console input menu
162   //
163   for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) {
164     NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
165 
166     NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
167     if (NewConsoleContext->IsActive) {
168       ConDevicePath = AppendDevicePathInstance (
169                         ConDevicePath,
170                         NewConsoleContext->DevicePath
171                         );
172     }
173   }
174 
175   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
176     NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
177 
178     NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
179     if (((NewTerminalContext->IsConIn != 0) && (UpdatePageId == FORM_CON_IN_ID)) ||
180         ((NewTerminalContext->IsConOut != 0)  && (UpdatePageId == FORM_CON_OUT_ID)) ||
181         ((NewTerminalContext->IsStdErr  != 0) && (UpdatePageId == FORM_CON_ERR_ID))
182         ) {
183       Vendor.Header.Type    = MESSAGING_DEVICE_PATH;
184       Vendor.Header.SubType = MSG_VENDOR_DP;
185 
186       ASSERT (NewTerminalContext->TerminalType < (ARRAY_SIZE (TerminalTypeGuid)));
187       CopyMem (
188         &Vendor.Guid,
189         &TerminalTypeGuid[NewTerminalContext->TerminalType],
190         sizeof (EFI_GUID)
191         );
192       SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
193       TerminalDevicePath = AppendDevicePathNode (
194                             NewTerminalContext->DevicePath,
195                             (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
196                             );
197       ASSERT (TerminalDevicePath != NULL);
198       ChangeTerminalDevicePath (TerminalDevicePath, TRUE);
199       ConDevicePath = AppendDevicePathInstance (
200                         ConDevicePath,
201                         TerminalDevicePath
202                         );
203     }
204   }
205 
206   if (ConDevicePath != NULL) {
207     Status = gRT->SetVariable (
208                     ConsoleName,
209                     &gEfiGlobalVariableGuid,
210                     VAR_FLAG,
211                     GetDevicePathSize (ConDevicePath),
212                     ConDevicePath
213                     );
214     if (EFI_ERROR (Status)) {
215       return Status;
216     }
217   }
218 
219   return EFI_SUCCESS;
220 
221 }
222 
223 /**
224   This function delete and build multi-instance device path ConIn
225   console device.
226 
227   @retval EFI_SUCCESS    The function complete successfully.
228   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
229 **/
230 EFI_STATUS
Var_UpdateConsoleInpOption(VOID)231 Var_UpdateConsoleInpOption (
232   VOID
233   )
234 {
235   return Var_UpdateConsoleOption (L"ConIn", &ConsoleInpMenu, FORM_CON_IN_ID);
236 }
237 
238 /**
239   This function delete and build multi-instance device path ConOut
240   console device.
241 
242   @retval EFI_SUCCESS    The function complete successfully.
243   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
244 **/
245 EFI_STATUS
Var_UpdateConsoleOutOption(VOID)246 Var_UpdateConsoleOutOption (
247   VOID
248   )
249 {
250   return Var_UpdateConsoleOption (L"ConOut", &ConsoleOutMenu, FORM_CON_OUT_ID);
251 }
252 
253 /**
254   This function delete and build multi-instance device path ErrOut
255   console device.
256 
257   @retval EFI_SUCCESS    The function complete successfully.
258   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
259 **/
260 EFI_STATUS
Var_UpdateErrorOutOption(VOID)261 Var_UpdateErrorOutOption (
262   VOID
263   )
264 {
265   return Var_UpdateConsoleOption (L"ErrOut", &ConsoleErrMenu, FORM_CON_ERR_ID);
266 }
267 
268 /**
269   This function create a currently loaded Drive Option from
270   the BMM. It then appends this Driver Option to the end of
271   the "DriverOrder" list. It append this Driver Opotion to the end
272   of DriverOptionMenu.
273 
274   @param CallbackData    The BMM context data.
275   @param HiiHandle       The HII handle associated with the BMM formset.
276   @param DescriptionData The description of this driver option.
277   @param OptionalData    The optional load option.
278   @param ForceReconnect  If to force reconnect.
279 
280   @retval other                Contain some errors when excuting this function.See function
281                                EfiBootManagerInitializeLoadOption/EfiBootManagerAddLoadOptionVariabl
282                                for detail return information.
283   @retval EFI_SUCCESS          If function completes successfully.
284 
285 **/
286 EFI_STATUS
Var_UpdateDriverOption(IN BMM_CALLBACK_DATA * CallbackData,IN EFI_HII_HANDLE HiiHandle,IN UINT16 * DescriptionData,IN UINT16 * OptionalData,IN UINT8 ForceReconnect)287 Var_UpdateDriverOption (
288   IN  BMM_CALLBACK_DATA         *CallbackData,
289   IN  EFI_HII_HANDLE            HiiHandle,
290   IN  UINT16                    *DescriptionData,
291   IN  UINT16                    *OptionalData,
292   IN  UINT8                     ForceReconnect
293   )
294 {
295   UINT16          Index;
296   UINT16          DriverString[12];
297   BM_MENU_ENTRY   *NewMenuEntry;
298   BM_LOAD_CONTEXT *NewLoadContext;
299   BOOLEAN         OptionalDataExist;
300   EFI_STATUS      Status;
301   EFI_BOOT_MANAGER_LOAD_OPTION  LoadOption;
302   UINT8                         *OptionalDesData;
303   UINT32                        OptionalDataSize;
304 
305   OptionalDataExist = FALSE;
306   OptionalDesData = NULL;
307   OptionalDataSize = 0;
308 
309   Index             = BOpt_GetDriverOptionNumber ();
310   UnicodeSPrint (
311     DriverString,
312     sizeof (DriverString),
313     L"Driver%04x",
314     Index
315     );
316 
317   if (*DescriptionData == 0x0000) {
318     StrCpyS (DescriptionData, MAX_MENU_NUMBER, DriverString);
319   }
320 
321   if (*OptionalData != 0x0000) {
322     OptionalDataExist = TRUE;
323     OptionalDesData = (UINT8 *)OptionalData;
324     OptionalDataSize = (UINT32)StrSize (OptionalData);
325   }
326 
327   NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
328   if (NULL == NewMenuEntry) {
329     return EFI_OUT_OF_RESOURCES;
330   }
331 
332   Status = EfiBootManagerInitializeLoadOption (
333              &LoadOption,
334              Index,
335              LoadOptionTypeDriver,
336              LOAD_OPTION_ACTIVE | (ForceReconnect << 1),
337              DescriptionData,
338              CallbackData->LoadContext->FilePathList,
339              OptionalDesData,
340              OptionalDataSize
341            );
342   if (EFI_ERROR (Status)){
343     return Status;
344   }
345 
346   Status = EfiBootManagerAddLoadOptionVariable (&LoadOption,(UINTN) -1 );
347   if (EFI_ERROR (Status)) {
348     EfiBootManagerFreeLoadOption(&LoadOption);
349     return Status;
350   }
351 
352   NewLoadContext                  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
353   NewLoadContext->Deleted         = FALSE;
354   NewLoadContext->Attributes = LoadOption.Attributes;
355   NewLoadContext->FilePathListLength = (UINT16)GetDevicePathSize (LoadOption.FilePath);
356 
357   NewLoadContext->Description = AllocateZeroPool (StrSize (DescriptionData));
358   ASSERT (NewLoadContext->Description != NULL);
359   NewMenuEntry->DisplayString = NewLoadContext->Description;
360   CopyMem (
361     NewLoadContext->Description,
362     LoadOption.Description,
363     StrSize (DescriptionData)
364     );
365 
366   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
367   ASSERT (NewLoadContext->FilePathList != NULL);
368   CopyMem (
369     NewLoadContext->FilePathList,
370     LoadOption.FilePath,
371     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
372     );
373 
374   NewMenuEntry->HelpString    = UiDevicePathToStr (NewLoadContext->FilePathList);
375   NewMenuEntry->OptionNumber  = Index;
376   NewMenuEntry->DisplayStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->DisplayString, NULL);
377   NewMenuEntry->HelpStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->HelpString, NULL);
378 
379   if (OptionalDataExist) {
380     NewLoadContext->OptionalData = AllocateZeroPool (LoadOption.OptionalDataSize);
381     ASSERT (NewLoadContext->OptionalData != NULL);
382     CopyMem (
383       NewLoadContext->OptionalData,
384       LoadOption.OptionalData,
385       LoadOption.OptionalDataSize
386       );
387   }
388 
389   InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
390   DriverOptionMenu.MenuNumber++;
391 
392   EfiBootManagerFreeLoadOption(&LoadOption);
393 
394   return EFI_SUCCESS;
395 }
396 
397 /**
398   This function create a currently loaded Boot Option from
399   the BMM. It then appends this Boot Option to the end of
400   the "BootOrder" list. It also append this Boot Opotion to the end
401   of BootOptionMenu.
402 
403   @param CallbackData    The BMM context data.
404 
405   @retval other                Contain some errors when excuting this function. See function
406                                EfiBootManagerInitializeLoadOption/EfiBootManagerAddLoadOptionVariabl
407                                for detail return information.
408   @retval EFI_SUCCESS          If function completes successfully.
409 
410 **/
411 EFI_STATUS
Var_UpdateBootOption(IN BMM_CALLBACK_DATA * CallbackData)412 Var_UpdateBootOption (
413   IN  BMM_CALLBACK_DATA              *CallbackData
414   )
415 {
416   UINT16          BootString[10];
417   UINT16          Index;
418   BM_MENU_ENTRY   *NewMenuEntry;
419   BM_LOAD_CONTEXT *NewLoadContext;
420   BOOLEAN         OptionalDataExist;
421   EFI_STATUS      Status;
422   BMM_FAKE_NV_DATA  *NvRamMap;
423   EFI_BOOT_MANAGER_LOAD_OPTION  LoadOption;
424   UINT8                         *OptionalData;
425   UINT32                        OptionalDataSize;
426 
427   OptionalDataExist = FALSE;
428   NvRamMap = &CallbackData->BmmFakeNvData;
429   OptionalData = NULL;
430   OptionalDataSize = 0;
431 
432   Index = BOpt_GetBootOptionNumber () ;
433   UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", Index);
434 
435   if (NvRamMap->BootDescriptionData[0] == 0x0000) {
436     StrCpyS (NvRamMap->BootDescriptionData, sizeof (NvRamMap->BootDescriptionData) / sizeof (NvRamMap->BootDescriptionData[0]), BootString);
437   }
438 
439   if (NvRamMap->BootOptionalData[0] != 0x0000) {
440     OptionalDataExist = TRUE;
441     OptionalData = (UINT8 *)NvRamMap->BootOptionalData;
442     OptionalDataSize = (UINT32)StrSize (NvRamMap->BootOptionalData);
443   }
444 
445   NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
446   if (NULL == NewMenuEntry) {
447     return EFI_OUT_OF_RESOURCES;
448   }
449 
450   Status = EfiBootManagerInitializeLoadOption (
451              &LoadOption,
452              Index,
453              LoadOptionTypeBoot,
454              LOAD_OPTION_ACTIVE,
455              NvRamMap->BootDescriptionData,
456              CallbackData->LoadContext->FilePathList,
457              OptionalData,
458              OptionalDataSize
459            );
460   if (EFI_ERROR (Status)){
461     return Status;
462   }
463 
464   Status = EfiBootManagerAddLoadOptionVariable (&LoadOption,(UINTN) -1 );
465   if (EFI_ERROR (Status)) {
466     EfiBootManagerFreeLoadOption(&LoadOption);
467     return Status;
468   }
469 
470   NewLoadContext                  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
471   NewLoadContext->Deleted         = FALSE;
472   NewLoadContext->Attributes = LoadOption.Attributes;
473   NewLoadContext->FilePathListLength = (UINT16) GetDevicePathSize (LoadOption.FilePath);
474 
475   NewLoadContext->Description = AllocateZeroPool (StrSize (NvRamMap->BootDescriptionData));
476   ASSERT (NewLoadContext->Description != NULL);
477 
478   NewMenuEntry->DisplayString = NewLoadContext->Description;
479 
480   CopyMem (
481     NewLoadContext->Description,
482     LoadOption.Description,
483     StrSize (NvRamMap->BootDescriptionData)
484     );
485 
486   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
487   ASSERT (NewLoadContext->FilePathList != NULL);
488   CopyMem (
489     NewLoadContext->FilePathList,
490     LoadOption.FilePath,
491     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
492     );
493 
494   NewMenuEntry->HelpString    = UiDevicePathToStr (NewLoadContext->FilePathList);
495   NewMenuEntry->OptionNumber  = Index;
496   NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
497   NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, NewMenuEntry->HelpString, NULL);
498 
499   if (OptionalDataExist) {
500     NewLoadContext->OptionalData = AllocateZeroPool (LoadOption.OptionalDataSize);
501     ASSERT (NewLoadContext->OptionalData != NULL);
502     CopyMem (
503       NewLoadContext->OptionalData,
504       LoadOption.OptionalData,
505       LoadOption.OptionalDataSize
506       );
507   }
508 
509   InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
510   BootOptionMenu.MenuNumber++;
511 
512   EfiBootManagerFreeLoadOption(&LoadOption);
513 
514   return EFI_SUCCESS;
515 }
516 
517 /**
518   This function update the "BootNext" EFI Variable. If there is
519   no "BootNext" specified in BMM, this EFI Variable is deleted.
520   It also update the BMM context data specified the "BootNext"
521   vaule.
522 
523   @param CallbackData    The BMM context data.
524 
525   @retval EFI_SUCCESS    The function complete successfully.
526   @return                The EFI variable can be saved. See gRT->SetVariable
527                          for detail return information.
528 
529 **/
530 EFI_STATUS
Var_UpdateBootNext(IN BMM_CALLBACK_DATA * CallbackData)531 Var_UpdateBootNext (
532   IN BMM_CALLBACK_DATA            *CallbackData
533   )
534 {
535   BM_MENU_ENTRY     *NewMenuEntry;
536   BM_LOAD_CONTEXT   *NewLoadContext;
537   BMM_FAKE_NV_DATA  *CurrentFakeNVMap;
538   UINT16            Index;
539   EFI_STATUS        Status;
540 
541   Status            = EFI_SUCCESS;
542   CurrentFakeNVMap  = &CallbackData->BmmFakeNvData;
543   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
544     NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
545     ASSERT (NULL != NewMenuEntry);
546 
547     NewLoadContext              = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
548     NewLoadContext->IsBootNext  = FALSE;
549   }
550 
551   if (CurrentFakeNVMap->BootNext == NONE_BOOTNEXT_VALUE) {
552     EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
553     return EFI_SUCCESS;
554   }
555 
556   NewMenuEntry = BOpt_GetMenuEntry (
557                   &BootOptionMenu,
558                   CurrentFakeNVMap->BootNext
559                   );
560   ASSERT (NewMenuEntry != NULL);
561 
562   NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
563   Status = gRT->SetVariable (
564                   L"BootNext",
565                   &gEfiGlobalVariableGuid,
566                   VAR_FLAG,
567                   sizeof (UINT16),
568                   &NewMenuEntry->OptionNumber
569                   );
570   NewLoadContext->IsBootNext              = TRUE;
571   CallbackData->BmmOldFakeNVData.BootNext = CurrentFakeNVMap->BootNext;
572   return Status;
573 }
574 
575 /**
576   This function update the "BootOrder" EFI Variable based on
577   BMM Formset's NV map. It then refresh BootOptionMenu
578   with the new "BootOrder" list.
579 
580   @param CallbackData    The BMM context data.
581 
582   @retval EFI_SUCCESS             The function complete successfully.
583   @retval EFI_OUT_OF_RESOURCES    Not enough memory to complete the function.
584   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
585 
586 **/
587 EFI_STATUS
Var_UpdateBootOrder(IN BMM_CALLBACK_DATA * CallbackData)588 Var_UpdateBootOrder (
589   IN BMM_CALLBACK_DATA            *CallbackData
590   )
591 {
592   EFI_STATUS  Status;
593   UINT16      Index;
594   UINT16      OrderIndex;
595   UINT16      *BootOrder;
596   UINTN       BootOrderSize;
597   UINT16      OptionNumber;
598 
599   //
600   // First check whether BootOrder is present in current configuration
601   //
602   GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize);
603   if (BootOrder == NULL) {
604     return EFI_OUT_OF_RESOURCES;
605   }
606 
607   ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.BootOptionOrder) / sizeof (CallbackData->BmmFakeNvData.BootOptionOrder[0])));
608 
609   //
610   // OptionOrder is subset of BootOrder
611   //
612   for (OrderIndex = 0; (OrderIndex < BootOptionMenu.MenuNumber) && (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] != 0); OrderIndex++) {
613     for (Index = OrderIndex; Index < BootOrderSize / sizeof (UINT16); Index++) {
614       if ((BootOrder[Index] == (UINT16) (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] - 1)) && (OrderIndex != Index)) {
615         OptionNumber = BootOrder[Index];
616         CopyMem (&BootOrder[OrderIndex + 1], &BootOrder[OrderIndex], (Index - OrderIndex) * sizeof (UINT16));
617         BootOrder[OrderIndex] = OptionNumber;
618       }
619     }
620   }
621 
622   Status = gRT->SetVariable (
623                   L"BootOrder",
624                   &gEfiGlobalVariableGuid,
625                   VAR_FLAG,
626                   BootOrderSize,
627                   BootOrder
628                   );
629   FreePool (BootOrder);
630 
631   BOpt_FreeMenu (&BootOptionMenu);
632   BOpt_GetBootOptions (CallbackData);
633 
634   return Status;
635 
636 }
637 
638 /**
639   This function update the "DriverOrder" EFI Variable based on
640   BMM Formset's NV map. It then refresh DriverOptionMenu
641   with the new "DriverOrder" list.
642 
643   @param CallbackData    The BMM context data.
644 
645   @retval EFI_SUCCESS           The function complete successfully.
646   @retval EFI_OUT_OF_RESOURCES  Not enough memory to complete the function.
647   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
648 
649 **/
650 EFI_STATUS
Var_UpdateDriverOrder(IN BMM_CALLBACK_DATA * CallbackData)651 Var_UpdateDriverOrder (
652   IN BMM_CALLBACK_DATA            *CallbackData
653   )
654 {
655   EFI_STATUS  Status;
656   UINT16      Index;
657   UINT16      *DriverOrderList;
658   UINT16      *NewDriverOrderList;
659   UINTN       DriverOrderListSize;
660 
661   DriverOrderList     = NULL;
662   DriverOrderListSize = 0;
663 
664   //
665   // First check whether DriverOrder is present in current configuration
666   //
667   GetEfiGlobalVariable2 (L"DriverOrder", (VOID **) &DriverOrderList, &DriverOrderListSize);
668   NewDriverOrderList = AllocateZeroPool (DriverOrderListSize);
669 
670   if (NewDriverOrderList == NULL) {
671     return EFI_OUT_OF_RESOURCES;
672   }
673   //
674   // If exists, delete it to hold new DriverOrder
675   //
676   if (DriverOrderList != NULL) {
677     EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
678     FreePool (DriverOrderList);
679   }
680 
681   ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder) / sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder[0])));
682   for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
683     NewDriverOrderList[Index] = (UINT16) (CallbackData->BmmFakeNvData.DriverOptionOrder[Index] - 1);
684   }
685 
686   Status = gRT->SetVariable (
687                   L"DriverOrder",
688                   &gEfiGlobalVariableGuid,
689                   VAR_FLAG,
690                   DriverOrderListSize,
691                   NewDriverOrderList
692                   );
693   if (EFI_ERROR (Status)) {
694     return Status;
695   }
696 
697   BOpt_FreeMenu (&DriverOptionMenu);
698   BOpt_GetDriverOptions (CallbackData);
699   return EFI_SUCCESS;
700 }
701 
702 /**
703   Update the Text Mode of Console.
704 
705   @param CallbackData  The context data for BMM.
706 
707   @retval EFI_SUCCSS If the Text Mode of Console is updated.
708   @return Other value if the Text Mode of Console is not updated.
709 
710 **/
711 EFI_STATUS
Var_UpdateConMode(IN BMM_CALLBACK_DATA * CallbackData)712 Var_UpdateConMode (
713   IN BMM_CALLBACK_DATA            *CallbackData
714   )
715 {
716   EFI_STATUS        Status;
717   UINTN             Mode;
718   CONSOLE_OUT_MODE  ModeInfo;
719 
720   Mode = CallbackData->BmmFakeNvData.ConsoleOutMode;
721 
722   Status = gST->ConOut->QueryMode (gST->ConOut, Mode, &(ModeInfo.Column), &(ModeInfo.Row));
723   if (!EFI_ERROR(Status)) {
724     Status = PcdSet32S (PcdSetupConOutColumn, (UINT32) ModeInfo.Column);
725     if (!EFI_ERROR (Status)) {
726       Status = PcdSet32S (PcdSetupConOutRow, (UINT32) ModeInfo.Row);
727     }
728   }
729 
730   return Status;
731 }
732