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 "BootMaint.h"
10 
11 /**
12   Delete Boot Option that represent a Deleted state in BootOptionMenu.
13   After deleting this boot option, call Var_ChangeBootOrder to
14   make sure BootOrder is in valid state.
15 
16   @retval EFI_SUCCESS   If all boot load option EFI Variables corresponding to
17                         BM_LOAD_CONTEXT marked for deletion is deleted.
18   @retval EFI_NOT_FOUND If can not find the boot option want to be deleted.
19   @return Others        If failed to update the "BootOrder" variable after deletion.
20 
21 **/
22 EFI_STATUS
Var_DelBootOption(VOID)23 Var_DelBootOption (
24   VOID
25   )
26 {
27   BM_MENU_ENTRY   *NewMenuEntry;
28   BM_LOAD_CONTEXT *NewLoadContext;
29   UINT16          BootString[10];
30   EFI_STATUS      Status;
31   UINTN           Index;
32   UINTN           Index2;
33 
34   Status  = EFI_SUCCESS;
35   Index2  = 0;
36   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
37     NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, (Index - Index2));
38     if (NULL == NewMenuEntry) {
39       return EFI_NOT_FOUND;
40     }
41 
42     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
43     if (!NewLoadContext->Deleted) {
44       continue;
45     }
46 
47     UnicodeSPrint (
48       BootString,
49       sizeof (BootString),
50       L"Boot%04x",
51       NewMenuEntry->OptionNumber
52       );
53 
54     EfiLibDeleteVariable (BootString, &gEfiGlobalVariableGuid);
55     Index2++;
56     //
57     // If current Load Option is the same as BootNext,
58     // must delete BootNext in order to make sure
59     // there will be no panic on next boot
60     //
61     if (NewLoadContext->IsBootNext) {
62       EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
63     }
64 
65     RemoveEntryList (&NewMenuEntry->Link);
66     BOpt_DestroyMenuEntry (NewMenuEntry);
67     NewMenuEntry = NULL;
68   }
69 
70   BootOptionMenu.MenuNumber -= Index2;
71 
72   Status = Var_ChangeBootOrder ();
73   return Status;
74 }
75 
76 /**
77   After any operation on Boot####, there will be a discrepancy in BootOrder.
78   Since some are missing but in BootOrder, while some are present but are
79   not reflected by BootOrder. Then a function rebuild BootOrder from
80   scratch by content from BootOptionMenu is needed.
81 
82 
83 
84 
85   @retval  EFI_SUCCESS  The boot order is updated successfully.
86   @return               EFI_STATUS other than EFI_SUCCESS if failed to
87                         Set the "BootOrder" EFI Variable.
88 
89 **/
90 EFI_STATUS
Var_ChangeBootOrder(VOID)91 Var_ChangeBootOrder (
92   VOID
93   )
94 {
95 
96   EFI_STATUS    Status;
97   BM_MENU_ENTRY *NewMenuEntry;
98   UINT16        *BootOrderList;
99   UINT16        *BootOrderListPtr;
100   UINTN         BootOrderListSize;
101   UINTN         Index;
102 
103   BootOrderList     = NULL;
104   BootOrderListSize = 0;
105 
106   //
107   // First check whether BootOrder is present in current configuration
108   //
109   BootOrderList = BdsLibGetVariableAndSize (
110                     L"BootOrder",
111                     &gEfiGlobalVariableGuid,
112                     &BootOrderListSize
113                     );
114 
115   //
116   // If exists, delete it to hold new BootOrder
117   //
118   if (BootOrderList != NULL) {
119     EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
120     FreePool (BootOrderList);
121     BootOrderList = NULL;
122   }
123   //
124   // Maybe here should be some check method to ensure that
125   // no new added boot options will be added
126   // but the setup engine now will give only one callback
127   // that is to say, user are granted only one chance to
128   // decide whether the boot option will be added or not
129   // there should be no indictor to show whether this
130   // is a "new" boot option
131   //
132   BootOrderListSize = BootOptionMenu.MenuNumber;
133 
134   if (BootOrderListSize > 0) {
135     BootOrderList = AllocateZeroPool (BootOrderListSize * sizeof (UINT16));
136     ASSERT (BootOrderList != NULL);
137     BootOrderListPtr = BootOrderList;
138 
139     //
140     // Get all current used Boot#### from BootOptionMenu.
141     // OptionNumber in each BM_LOAD_OPTION is really its
142     // #### value.
143     //
144     for (Index = 0; Index < BootOrderListSize; Index++) {
145       NewMenuEntry    = BOpt_GetMenuEntry (&BootOptionMenu, Index);
146       *BootOrderList  = (UINT16) NewMenuEntry->OptionNumber;
147       BootOrderList++;
148     }
149 
150     BootOrderList = BootOrderListPtr;
151 
152     //
153     // After building the BootOrderList, write it back
154     //
155     Status = gRT->SetVariable (
156                     L"BootOrder",
157                     &gEfiGlobalVariableGuid,
158                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
159                     BootOrderListSize * sizeof (UINT16),
160                     BootOrderList
161                     );
162     //
163     // Changing variable without increasing its size with current variable implementation shouldn't fail.
164     //
165     ASSERT_EFI_ERROR (Status);
166   }
167   return EFI_SUCCESS;
168 }
169 
170 /**
171   Delete Load Option that represent a Deleted state in BootOptionMenu.
172   After deleting this Driver option, call Var_ChangeDriverOrder to
173   make sure DriverOrder is in valid state.
174 
175   @retval EFI_SUCCESS       Load Option is successfully updated.
176   @retval EFI_NOT_FOUND     Fail to find the driver option want to be deleted.
177   @return Other value than EFI_SUCCESS if failed to update "Driver Order" EFI
178           Variable.
179 
180 **/
181 EFI_STATUS
Var_DelDriverOption(VOID)182 Var_DelDriverOption (
183   VOID
184   )
185 {
186   BM_MENU_ENTRY   *NewMenuEntry;
187   BM_LOAD_CONTEXT *NewLoadContext;
188   UINT16          DriverString[12];
189   EFI_STATUS      Status;
190   UINTN           Index;
191   UINTN           Index2;
192 
193   Status  = EFI_SUCCESS;
194   Index2  = 0;
195   for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
196     NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, (Index - Index2));
197     if (NULL == NewMenuEntry) {
198       return EFI_NOT_FOUND;
199     }
200 
201     NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
202     if (!NewLoadContext->Deleted) {
203       continue;
204     }
205 
206     UnicodeSPrint (
207       DriverString,
208       sizeof (DriverString),
209       L"Driver%04x",
210       NewMenuEntry->OptionNumber
211       );
212 
213     EfiLibDeleteVariable (DriverString, &gEfiGlobalVariableGuid);
214     Index2++;
215 
216     RemoveEntryList (&NewMenuEntry->Link);
217     BOpt_DestroyMenuEntry (NewMenuEntry);
218     NewMenuEntry = NULL;
219   }
220 
221   DriverOptionMenu.MenuNumber -= Index2;
222 
223   Status = Var_ChangeDriverOrder ();
224   return Status;
225 }
226 
227 /**
228   After any operation on Driver####, there will be a discrepancy in
229   DriverOrder. Since some are missing but in DriverOrder, while some
230   are present but are not reflected by DriverOrder. Then a function
231   rebuild DriverOrder from scratch by content from DriverOptionMenu is
232   needed.
233 
234   @retval  EFI_SUCCESS  The driver order is updated successfully.
235   @return  Other status than EFI_SUCCESS if failed to set the "DriverOrder" EFI Variable.
236 
237 **/
238 EFI_STATUS
Var_ChangeDriverOrder(VOID)239 Var_ChangeDriverOrder (
240   VOID
241   )
242 {
243   EFI_STATUS    Status;
244   BM_MENU_ENTRY *NewMenuEntry;
245   UINT16        *DriverOrderList;
246   UINT16        *DriverOrderListPtr;
247   UINTN         DriverOrderListSize;
248   UINTN         Index;
249 
250   DriverOrderList     = NULL;
251   DriverOrderListSize = 0;
252 
253   //
254   // First check whether DriverOrder is present in current configuration
255   //
256   DriverOrderList = BdsLibGetVariableAndSize (
257                       L"DriverOrder",
258                       &gEfiGlobalVariableGuid,
259                       &DriverOrderListSize
260                       );
261 
262   //
263   // If exists, delete it to hold new DriverOrder
264   //
265   if (DriverOrderList != NULL) {
266     EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
267     FreePool (DriverOrderList);
268     DriverOrderList = NULL;
269   }
270 
271   DriverOrderListSize = DriverOptionMenu.MenuNumber;
272 
273   if (DriverOrderListSize > 0) {
274     DriverOrderList = AllocateZeroPool (DriverOrderListSize * sizeof (UINT16));
275     ASSERT (DriverOrderList != NULL);
276     DriverOrderListPtr = DriverOrderList;
277 
278     //
279     // Get all current used Driver#### from DriverOptionMenu.
280     // OptionNumber in each BM_LOAD_OPTION is really its
281     // #### value.
282     //
283     for (Index = 0; Index < DriverOrderListSize; Index++) {
284       NewMenuEntry      = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
285       *DriverOrderList  = (UINT16) NewMenuEntry->OptionNumber;
286       DriverOrderList++;
287     }
288 
289     DriverOrderList = DriverOrderListPtr;
290 
291     //
292     // After building the DriverOrderList, write it back
293     //
294     Status = gRT->SetVariable (
295                     L"DriverOrder",
296                     &gEfiGlobalVariableGuid,
297                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
298                     DriverOrderListSize * sizeof (UINT16),
299                     DriverOrderList
300                     );
301     //
302     // Changing variable without increasing its size with current variable implementation shouldn't fail.
303     //
304     ASSERT_EFI_ERROR (Status);
305   }
306   return EFI_SUCCESS;
307 }
308 
309 
310 
311 /**
312   This function delete and build multi-instance device path for
313   specified type of console device.
314 
315   This function clear the EFI variable defined by ConsoleName and
316   gEfiGlobalVariableGuid. It then build the multi-instance device
317   path by appending the device path of the Console (In/Out/Err) instance
318   in ConsoleMenu. Then it scan all corresponding console device by
319   scanning Terminal (built from device supporting Serial I/O instances)
320   devices in TerminalMenu. At last, it save a EFI variable specifed
321   by ConsoleName and gEfiGlobalVariableGuid.
322 
323   @param ConsoleName     The name for the console device type. They are
324                          usually "ConIn", "ConOut" and "ErrOut".
325   @param ConsoleMenu     The console memu which is a list of console devices.
326   @param UpdatePageId    The flag specifying which type of console device
327                          to be processed.
328 
329   @retval EFI_SUCCESS    The function complete successfully.
330   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
331 
332 **/
333 EFI_STATUS
Var_UpdateConsoleOption(IN UINT16 * ConsoleName,IN BM_MENU_OPTION * ConsoleMenu,IN UINT16 UpdatePageId)334 Var_UpdateConsoleOption (
335   IN UINT16                     *ConsoleName,
336   IN BM_MENU_OPTION             *ConsoleMenu,
337   IN UINT16                     UpdatePageId
338   )
339 {
340   EFI_DEVICE_PATH_PROTOCOL  *ConDevicePath;
341   BM_MENU_ENTRY             *NewMenuEntry;
342   BM_CONSOLE_CONTEXT        *NewConsoleContext;
343   BM_TERMINAL_CONTEXT       *NewTerminalContext;
344   EFI_STATUS                Status;
345   VENDOR_DEVICE_PATH        Vendor;
346   EFI_DEVICE_PATH_PROTOCOL  *TerminalDevicePath;
347   UINTN                     Index;
348 
349   ConDevicePath = EfiLibGetVariable (ConsoleName, &gEfiGlobalVariableGuid);
350   if (ConDevicePath != NULL) {
351     EfiLibDeleteVariable (ConsoleName, &gEfiGlobalVariableGuid);
352     FreePool (ConDevicePath);
353     ConDevicePath = NULL;
354   };
355 
356   //
357   // First add all console input device from console input menu
358   //
359   for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) {
360     NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
361 
362     NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
363     if (NewConsoleContext->IsActive) {
364       ConDevicePath = AppendDevicePathInstance (
365                         ConDevicePath,
366                         NewConsoleContext->DevicePath
367                         );
368     }
369   }
370 
371   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
372     NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
373 
374     NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
375     if (((NewTerminalContext->IsConIn != 0) && (UpdatePageId == FORM_CON_IN_ID)) ||
376         ((NewTerminalContext->IsConOut != 0)  && (UpdatePageId == FORM_CON_OUT_ID)) ||
377         ((NewTerminalContext->IsStdErr  != 0) && (UpdatePageId == FORM_CON_ERR_ID))
378         ) {
379       Vendor.Header.Type    = MESSAGING_DEVICE_PATH;
380       Vendor.Header.SubType = MSG_VENDOR_DP;
381 
382       ASSERT (NewTerminalContext->TerminalType < (ARRAY_SIZE (TerminalTypeGuid)));
383       CopyMem (
384         &Vendor.Guid,
385         &TerminalTypeGuid[NewTerminalContext->TerminalType],
386         sizeof (EFI_GUID)
387         );
388       SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
389       TerminalDevicePath = AppendDevicePathNode (
390                             NewTerminalContext->DevicePath,
391                             (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
392                             );
393       ASSERT (TerminalDevicePath != NULL);
394       ChangeTerminalDevicePath (&TerminalDevicePath, TRUE);
395       ConDevicePath = AppendDevicePathInstance (
396                         ConDevicePath,
397                         TerminalDevicePath
398                         );
399     }
400   }
401 
402   if (ConDevicePath != NULL) {
403     Status = gRT->SetVariable (
404                     ConsoleName,
405                     &gEfiGlobalVariableGuid,
406                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
407                     GetDevicePathSize (ConDevicePath),
408                     ConDevicePath
409                     );
410     if (EFI_ERROR (Status)) {
411       return Status;
412     }
413   }
414 
415   return EFI_SUCCESS;
416 
417 }
418 
419 /**
420   This function delete and build multi-instance device path ConIn
421   console device.
422 
423   @retval EFI_SUCCESS    The function complete successfully.
424   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
425 **/
426 EFI_STATUS
Var_UpdateConsoleInpOption(VOID)427 Var_UpdateConsoleInpOption (
428   VOID
429   )
430 {
431   return Var_UpdateConsoleOption (L"ConIn", &ConsoleInpMenu, FORM_CON_IN_ID);
432 }
433 
434 /**
435   This function delete and build multi-instance device path ConOut
436   console device.
437 
438   @retval EFI_SUCCESS    The function complete successfully.
439   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
440 **/
441 EFI_STATUS
Var_UpdateConsoleOutOption(VOID)442 Var_UpdateConsoleOutOption (
443   VOID
444   )
445 {
446   return Var_UpdateConsoleOption (L"ConOut", &ConsoleOutMenu, FORM_CON_OUT_ID);
447 }
448 
449 /**
450   This function delete and build multi-instance device path ErrOut
451   console device.
452 
453   @retval EFI_SUCCESS    The function complete successfully.
454   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
455 **/
456 EFI_STATUS
Var_UpdateErrorOutOption(VOID)457 Var_UpdateErrorOutOption (
458   VOID
459   )
460 {
461   return Var_UpdateConsoleOption (L"ErrOut", &ConsoleErrMenu, FORM_CON_ERR_ID);
462 }
463 
464 /**
465   This function create a currently loaded Drive Option from
466   the BMM. It then appends this Driver Option to the end of
467   the "DriverOrder" list. It append this Driver Opotion to the end
468   of DriverOptionMenu.
469 
470   @param CallbackData    The BMM context data.
471   @param HiiHandle       The HII handle associated with the BMM formset.
472   @param DescriptionData The description of this driver option.
473   @param OptionalData    The optional load option.
474   @param ForceReconnect  If to force reconnect.
475 
476   @retval EFI_OUT_OF_RESOURCES If not enought memory to complete the operation.
477   @retval EFI_SUCCESS          If function completes successfully.
478 
479 **/
480 EFI_STATUS
Var_UpdateDriverOption(IN BMM_CALLBACK_DATA * CallbackData,IN EFI_HII_HANDLE HiiHandle,IN UINT16 * DescriptionData,IN UINT16 * OptionalData,IN UINT8 ForceReconnect)481 Var_UpdateDriverOption (
482   IN  BMM_CALLBACK_DATA         *CallbackData,
483   IN  EFI_HII_HANDLE            HiiHandle,
484   IN  UINT16                    *DescriptionData,
485   IN  UINT16                    *OptionalData,
486   IN  UINT8                     ForceReconnect
487   )
488 {
489   UINT16          Index;
490   UINT16          *DriverOrderList;
491   UINT16          *NewDriverOrderList;
492   UINT16          DriverString[12];
493   UINTN           DriverOrderListSize;
494   VOID            *Buffer;
495   UINTN           BufferSize;
496   UINT8           *Ptr;
497   BM_MENU_ENTRY   *NewMenuEntry;
498   BM_LOAD_CONTEXT *NewLoadContext;
499   BOOLEAN         OptionalDataExist;
500   EFI_STATUS      Status;
501 
502   OptionalDataExist = FALSE;
503 
504   Index             = BOpt_GetDriverOptionNumber ();
505   UnicodeSPrint (
506     DriverString,
507     sizeof (DriverString),
508     L"Driver%04x",
509     Index
510     );
511 
512   if (*DescriptionData == 0x0000) {
513     StrCpyS (DescriptionData, DESCRIPTION_DATA_SIZE, DriverString);
514   }
515 
516   BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (DescriptionData);
517   BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
518 
519   if (*OptionalData != 0x0000) {
520     OptionalDataExist = TRUE;
521     BufferSize += StrSize (OptionalData);
522   }
523 
524   Buffer = AllocateZeroPool (BufferSize);
525   if (NULL == Buffer) {
526     return EFI_OUT_OF_RESOURCES;
527   }
528 
529   NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
530   if (NULL == NewMenuEntry) {
531     FreePool (Buffer);
532     return EFI_OUT_OF_RESOURCES;
533   }
534 
535   NewLoadContext                  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
536   NewLoadContext->Deleted         = FALSE;
537   NewLoadContext->LoadOptionSize  = BufferSize;
538   Ptr = (UINT8 *) Buffer;
539   NewLoadContext->LoadOption = Ptr;
540   *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE | (ForceReconnect << 1);
541   NewLoadContext->Attributes = *((UINT32 *) Ptr);
542   NewLoadContext->IsActive = TRUE;
543   NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
544 
545   Ptr += sizeof (UINT32);
546   *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
547   NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
548 
549   Ptr += sizeof (UINT16);
550   CopyMem (
551     Ptr,
552     DescriptionData,
553     StrSize (DescriptionData)
554     );
555 
556   NewLoadContext->Description = AllocateZeroPool (StrSize (DescriptionData));
557   ASSERT (NewLoadContext->Description != NULL);
558   NewMenuEntry->DisplayString = NewLoadContext->Description;
559   CopyMem (
560     NewLoadContext->Description,
561     (VOID *) Ptr,
562     StrSize (DescriptionData)
563     );
564 
565   Ptr += StrSize (DescriptionData);
566   CopyMem (
567     Ptr,
568     CallbackData->LoadContext->FilePathList,
569     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
570     );
571 
572   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
573   ASSERT (NewLoadContext->FilePathList != NULL);
574 
575   CopyMem (
576     NewLoadContext->FilePathList,
577     (VOID *) Ptr,
578     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
579     );
580 
581   NewMenuEntry->HelpString    = DevicePathToStr (NewLoadContext->FilePathList);
582   NewMenuEntry->OptionNumber  = Index;
583   NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
584                                       CallbackData,
585                                       DriverOptionStrDepository
586                                       );
587   NewMenuEntry->DisplayStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->DisplayString, NULL);
588 
589   NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
590                                     CallbackData,
591                                     DriverOptionHelpStrDepository
592                                     );
593   NewMenuEntry->HelpStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->HelpString, NULL);
594 
595   if (OptionalDataExist) {
596     Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
597 
598     CopyMem (
599       Ptr,
600       OptionalData,
601       StrSize (OptionalData)
602       );
603   }
604 
605   Status = gRT->SetVariable (
606                   DriverString,
607                   &gEfiGlobalVariableGuid,
608                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
609                   BufferSize,
610                   Buffer
611                   );
612   if (!EFI_ERROR (Status)) {
613     DriverOrderList = BdsLibGetVariableAndSize (
614                         L"DriverOrder",
615                         &gEfiGlobalVariableGuid,
616                         &DriverOrderListSize
617                         );
618     NewDriverOrderList = AllocateZeroPool (DriverOrderListSize + sizeof (UINT16));
619     ASSERT (NewDriverOrderList != NULL);
620     if (DriverOrderList != NULL) {
621       CopyMem (NewDriverOrderList, DriverOrderList, DriverOrderListSize);
622       EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
623     }
624     NewDriverOrderList[DriverOrderListSize / sizeof (UINT16)] = Index;
625 
626     Status = gRT->SetVariable (
627                     L"DriverOrder",
628                     &gEfiGlobalVariableGuid,
629                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
630                     DriverOrderListSize + sizeof (UINT16),
631                     NewDriverOrderList
632                     );
633     if (DriverOrderList != NULL) {
634       FreePool (DriverOrderList);
635     }
636     DriverOrderList = NULL;
637     FreePool (NewDriverOrderList);
638     if (!EFI_ERROR (Status)) {
639       InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
640       DriverOptionMenu.MenuNumber++;
641 
642       //
643       // Update "change boot order" page used data, append the new add boot
644       // option at the end.
645       //
646       Index = 0;
647       while (CallbackData->BmmFakeNvData.DriverOptionOrder[Index] != 0) {
648         Index++;
649       }
650       CallbackData->BmmFakeNvData.DriverOptionOrder[Index] = (UINT32) (NewMenuEntry->OptionNumber + 1);
651 
652       *DescriptionData  = 0x0000;
653       *OptionalData     = 0x0000;
654     }
655   }
656   return EFI_SUCCESS;
657 }
658 
659 /**
660   This function create a currently loaded Boot Option from
661   the BMM. It then appends this Boot Option to the end of
662   the "BootOrder" list. It also append this Boot Opotion to the end
663   of BootOptionMenu.
664 
665   @param CallbackData    The BMM context data.
666   @param NvRamMap        The file explorer formset internal state.
667 
668   @retval EFI_OUT_OF_RESOURCES If not enought memory to complete the operation.
669   @retval EFI_SUCCESS          If function completes successfully.
670 
671 **/
672 EFI_STATUS
Var_UpdateBootOption(IN BMM_CALLBACK_DATA * CallbackData,IN FILE_EXPLORER_NV_DATA * NvRamMap)673 Var_UpdateBootOption (
674   IN  BMM_CALLBACK_DATA                   *CallbackData,
675   IN  FILE_EXPLORER_NV_DATA               *NvRamMap
676   )
677 {
678   UINT16          *BootOrderList;
679   UINT16          *NewBootOrderList;
680   UINTN           BootOrderListSize;
681   UINT16          BootString[10];
682   VOID            *Buffer;
683   UINTN           BufferSize;
684   UINT8           *Ptr;
685   UINT16          Index;
686   BM_MENU_ENTRY   *NewMenuEntry;
687   BM_LOAD_CONTEXT *NewLoadContext;
688   BOOLEAN         OptionalDataExist;
689   EFI_STATUS      Status;
690 
691   OptionalDataExist = FALSE;
692 
693   Index = BOpt_GetBootOptionNumber () ;
694   UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", Index);
695 
696   if (NvRamMap->BootDescriptionData[0] == 0x0000) {
697     StrCpyS (
698       NvRamMap->BootDescriptionData,
699       sizeof (NvRamMap->BootDescriptionData) / sizeof (NvRamMap->BootDescriptionData[0]),
700       BootString
701       );
702   }
703 
704   BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (NvRamMap->BootDescriptionData);
705   BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
706 
707   if (NvRamMap->BootOptionalData[0] != 0x0000) {
708     OptionalDataExist = TRUE;
709     BufferSize += StrSize (NvRamMap->BootOptionalData);
710   }
711 
712   Buffer = AllocateZeroPool (BufferSize);
713   if (NULL == Buffer) {
714     return EFI_OUT_OF_RESOURCES;
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   NewLoadContext->Deleted         = FALSE;
724   NewLoadContext->LoadOptionSize  = BufferSize;
725   Ptr = (UINT8 *) Buffer;
726   NewLoadContext->LoadOption = Ptr;
727   *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
728   NewLoadContext->Attributes = *((UINT32 *) Ptr);
729   NewLoadContext->IsActive = TRUE;
730   NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
731 
732   Ptr += sizeof (UINT32);
733   *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
734   NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
735   Ptr += sizeof (UINT16);
736 
737   CopyMem (
738     Ptr,
739     NvRamMap->BootDescriptionData,
740     StrSize (NvRamMap->BootDescriptionData)
741     );
742 
743   NewLoadContext->Description = AllocateZeroPool (StrSize (NvRamMap->BootDescriptionData));
744   ASSERT (NewLoadContext->Description != NULL);
745 
746   NewMenuEntry->DisplayString = NewLoadContext->Description;
747   CopyMem (
748     NewLoadContext->Description,
749     (VOID *) Ptr,
750     StrSize (NvRamMap->BootDescriptionData)
751     );
752 
753   Ptr += StrSize (NvRamMap->BootDescriptionData);
754   CopyMem (
755     Ptr,
756     CallbackData->LoadContext->FilePathList,
757     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
758     );
759 
760   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
761   ASSERT (NewLoadContext->FilePathList != NULL);
762 
763   CopyMem (
764     NewLoadContext->FilePathList,
765     (VOID *) Ptr,
766     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
767     );
768 
769   NewMenuEntry->HelpString    = DevicePathToStr (NewLoadContext->FilePathList);
770   NewMenuEntry->OptionNumber  = Index;
771   NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
772                                       CallbackData,
773                                       BootOptionStrDepository
774                                       );
775   NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->FeHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
776 
777   NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
778                                     CallbackData,
779                                     BootOptionHelpStrDepository
780                                     );
781   NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->FeHiiHandle, 0, NewMenuEntry->HelpString, NULL);
782 
783   if (OptionalDataExist) {
784     Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
785 
786     CopyMem (Ptr, NvRamMap->BootOptionalData, StrSize (NvRamMap->BootOptionalData));
787   }
788 
789   Status = gRT->SetVariable (
790                   BootString,
791                   &gEfiGlobalVariableGuid,
792                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
793                   BufferSize,
794                   Buffer
795                   );
796   if (!EFI_ERROR (Status)) {
797 
798     BootOrderList = BdsLibGetVariableAndSize (
799                       L"BootOrder",
800                       &gEfiGlobalVariableGuid,
801                       &BootOrderListSize
802                       );
803     ASSERT (BootOrderList != NULL);
804     NewBootOrderList = AllocateZeroPool (BootOrderListSize + sizeof (UINT16));
805     ASSERT (NewBootOrderList != NULL);
806     CopyMem (NewBootOrderList, BootOrderList, BootOrderListSize);
807     NewBootOrderList[BootOrderListSize / sizeof (UINT16)] = Index;
808 
809     if (BootOrderList != NULL) {
810       FreePool (BootOrderList);
811     }
812 
813     Status = gRT->SetVariable (
814                     L"BootOrder",
815                     &gEfiGlobalVariableGuid,
816                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
817                     BootOrderListSize + sizeof (UINT16),
818                     NewBootOrderList
819                     );
820     if (!EFI_ERROR (Status)) {
821 
822       FreePool (NewBootOrderList);
823       NewBootOrderList = NULL;
824       InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
825       BootOptionMenu.MenuNumber++;
826 
827       //
828       // Update "change driver order" page used data, append the new add driver
829       // option at the end.
830       //
831       Index = 0;
832       while (CallbackData->BmmFakeNvData.BootOptionOrder[Index] != 0) {
833         Index++;
834       }
835       CallbackData->BmmFakeNvData.BootOptionOrder[Index] = (UINT32) (NewMenuEntry->OptionNumber + 1);
836 
837       NvRamMap->BootDescriptionData[0]  = 0x0000;
838       NvRamMap->BootOptionalData[0]     = 0x0000;
839     }
840   }
841   return EFI_SUCCESS;
842 }
843 
844 /**
845   This function update the "BootNext" EFI Variable. If there is
846   no "BootNext" specified in BMM, this EFI Variable is deleted.
847   It also update the BMM context data specified the "BootNext"
848   vaule.
849 
850   @param CallbackData    The BMM context data.
851 
852   @retval EFI_SUCCESS    The function complete successfully.
853   @return                The EFI variable can be saved. See gRT->SetVariable
854                          for detail return information.
855 
856 **/
857 EFI_STATUS
Var_UpdateBootNext(IN BMM_CALLBACK_DATA * CallbackData)858 Var_UpdateBootNext (
859   IN BMM_CALLBACK_DATA            *CallbackData
860   )
861 {
862   BM_MENU_ENTRY     *NewMenuEntry;
863   BM_LOAD_CONTEXT   *NewLoadContext;
864   BMM_FAKE_NV_DATA  *CurrentFakeNVMap;
865   UINT16            Index;
866   EFI_STATUS        Status;
867 
868   Status            = EFI_SUCCESS;
869   CurrentFakeNVMap  = &CallbackData->BmmFakeNvData;
870   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
871     NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
872     ASSERT (NULL != NewMenuEntry);
873 
874     NewLoadContext              = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
875     NewLoadContext->IsBootNext  = FALSE;
876   }
877 
878   if (CurrentFakeNVMap->BootNext == BootOptionMenu.MenuNumber) {
879     EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
880     return EFI_SUCCESS;
881   }
882 
883   NewMenuEntry = BOpt_GetMenuEntry (
884                   &BootOptionMenu,
885                   CurrentFakeNVMap->BootNext
886                   );
887   ASSERT (NewMenuEntry != NULL);
888 
889   NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
890   Status = gRT->SetVariable (
891                   L"BootNext",
892                   &gEfiGlobalVariableGuid,
893                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
894                   sizeof (UINT16),
895                   &NewMenuEntry->OptionNumber
896                   );
897   NewLoadContext->IsBootNext              = TRUE;
898   CallbackData->BmmOldFakeNVData.BootNext = CurrentFakeNVMap->BootNext;
899   return Status;
900 }
901 
902 /**
903   This function update the "BootOrder" EFI Variable based on
904   BMM Formset's NV map. It then refresh BootOptionMenu
905   with the new "BootOrder" list.
906 
907   @param CallbackData    The BMM context data.
908 
909   @retval EFI_SUCCESS             The function complete successfully.
910   @retval EFI_OUT_OF_RESOURCES    Not enough memory to complete the function.
911   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
912 
913 **/
914 EFI_STATUS
Var_UpdateBootOrder(IN BMM_CALLBACK_DATA * CallbackData)915 Var_UpdateBootOrder (
916   IN BMM_CALLBACK_DATA            *CallbackData
917   )
918 {
919   EFI_STATUS  Status;
920   UINT16      Index;
921   UINT16      OrderIndex;
922   UINT16      *BootOrderList;
923   UINTN       BootOrderListSize;
924   UINT16      OptionNumber;
925 
926   BootOrderList     = NULL;
927   BootOrderListSize = 0;
928 
929   //
930   // First check whether BootOrder is present in current configuration
931   //
932   BootOrderList = BdsLibGetVariableAndSize (
933                     L"BootOrder",
934                     &gEfiGlobalVariableGuid,
935                     &BootOrderListSize
936                     );
937   if (BootOrderList == NULL) {
938     return EFI_OUT_OF_RESOURCES;
939   }
940 
941   ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.BootOptionOrder) / sizeof (CallbackData->BmmFakeNvData.BootOptionOrder[0])));
942 
943   for (OrderIndex = 0; (OrderIndex < BootOptionMenu.MenuNumber) && (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] != 0); OrderIndex++) {
944     for (Index = OrderIndex; Index < BootOrderListSize / sizeof (UINT16); Index++) {
945       if ((BootOrderList[Index] == (UINT16) (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] - 1)) && (OrderIndex != Index)) {
946         OptionNumber = BootOrderList[Index];
947         CopyMem (&BootOrderList[OrderIndex + 1], &BootOrderList[OrderIndex], (Index - OrderIndex) * sizeof (UINT16));
948         BootOrderList[OrderIndex] = OptionNumber;
949       }
950     }
951   }
952 
953   Status = gRT->SetVariable (
954                   L"BootOrder",
955                   &gEfiGlobalVariableGuid,
956                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
957                   BootOrderListSize,
958                   BootOrderList
959                   );
960   //
961   // Changing the content without increasing its size with current variable implementation shouldn't fail.
962   //
963   ASSERT_EFI_ERROR (Status);
964   FreePool (BootOrderList);
965 
966   GroupMultipleLegacyBootOption4SameType ();
967 
968   BOpt_FreeMenu (&BootOptionMenu);
969   BOpt_GetBootOptions (CallbackData);
970 
971   return Status;
972 
973 }
974 
975 /**
976   This function update the "DriverOrder" EFI Variable based on
977   BMM Formset's NV map. It then refresh DriverOptionMenu
978   with the new "DriverOrder" list.
979 
980   @param CallbackData    The BMM context data.
981 
982   @retval EFI_SUCCESS           The function complete successfully.
983   @retval EFI_OUT_OF_RESOURCES  Not enough memory to complete the function.
984   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
985 
986 **/
987 EFI_STATUS
Var_UpdateDriverOrder(IN BMM_CALLBACK_DATA * CallbackData)988 Var_UpdateDriverOrder (
989   IN BMM_CALLBACK_DATA            *CallbackData
990   )
991 {
992   EFI_STATUS  Status;
993   UINT16      Index;
994   UINT16      *DriverOrderList;
995   UINT16      *NewDriverOrderList;
996   UINTN       DriverOrderListSize;
997 
998   DriverOrderList     = NULL;
999   DriverOrderListSize = 0;
1000 
1001   //
1002   // First check whether DriverOrder is present in current configuration
1003   //
1004   DriverOrderList = BdsLibGetVariableAndSize (
1005                       L"DriverOrder",
1006                       &gEfiGlobalVariableGuid,
1007                       &DriverOrderListSize
1008                       );
1009 
1010   NewDriverOrderList = AllocateZeroPool (DriverOrderListSize);
1011 
1012   if (NewDriverOrderList == NULL) {
1013     return EFI_OUT_OF_RESOURCES;
1014   }
1015   //
1016   // If exists, delete it to hold new DriverOrder
1017   //
1018   if (DriverOrderList != NULL) {
1019     EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
1020     FreePool (DriverOrderList);
1021   }
1022 
1023   ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder) / sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder[0])));
1024   for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
1025     NewDriverOrderList[Index] = (UINT16) (CallbackData->BmmFakeNvData.DriverOptionOrder[Index] - 1);
1026   }
1027 
1028   Status = gRT->SetVariable (
1029                   L"DriverOrder",
1030                   &gEfiGlobalVariableGuid,
1031                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1032                   DriverOrderListSize,
1033                   NewDriverOrderList
1034                   );
1035   //
1036   // Changing the content without increasing its size with current variable implementation shouldn't fail.
1037   //
1038   ASSERT_EFI_ERROR (Status);
1039 
1040   BOpt_FreeMenu (&DriverOptionMenu);
1041   BOpt_GetDriverOptions (CallbackData);
1042   return EFI_SUCCESS;
1043 }
1044 
1045 /**
1046   Update the legacy BBS boot option. VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable
1047   is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid
1048   is also updated.
1049 
1050   @param CallbackData    The context data for BMM.
1051   @param FormId          The form id.
1052 
1053   @return EFI_SUCCESS           The function completed successfully.
1054   @retval EFI_NOT_FOUND         If VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable can be found.
1055   @retval EFI_OUT_OF_RESOURCES  Fail to allocate memory resource
1056 **/
1057 EFI_STATUS
Var_UpdateBBSOption(IN BMM_CALLBACK_DATA * CallbackData,IN EFI_FORM_ID FormId)1058 Var_UpdateBBSOption (
1059   IN BMM_CALLBACK_DATA            *CallbackData,
1060   IN EFI_FORM_ID                  FormId
1061   )
1062 {
1063   UINTN                       Index;
1064   UINTN                       Index2;
1065   VOID                        *BootOptionVar;
1066   CHAR16                      VarName[100];
1067   UINTN                       OptionSize;
1068   EFI_STATUS                  Status;
1069   UINT32                      *Attribute;
1070   BM_MENU_OPTION              *OptionMenu;
1071   UINT8                       *LegacyDev;
1072   UINT8                       *VarData;
1073   UINTN                       VarSize;
1074   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
1075   UINT8                       *OriginalPtr;
1076   UINT8                       *DisMap;
1077   UINTN                       Pos;
1078   UINTN                       Bit;
1079   UINT16                      *NewOrder;
1080   UINT16                      Tmp;
1081   UINT16                      *EnBootOption;
1082   UINTN                       EnBootOptionCount;
1083   UINT16                      *DisBootOption;
1084   UINTN                       DisBootOptionCount;
1085 
1086   DisMap              = NULL;
1087   NewOrder            = NULL;
1088 
1089   switch (FormId) {
1090     case FORM_SET_FD_ORDER_ID:
1091       OptionMenu            = (BM_MENU_OPTION *) &LegacyFDMenu;
1092       LegacyDev             = CallbackData->BmmFakeNvData.LegacyFD;
1093       CallbackData->BbsType = BBS_FLOPPY;
1094       break;
1095 
1096     case FORM_SET_HD_ORDER_ID:
1097       OptionMenu            = (BM_MENU_OPTION *) &LegacyHDMenu;
1098       LegacyDev             = CallbackData->BmmFakeNvData.LegacyHD;
1099       CallbackData->BbsType = BBS_HARDDISK;
1100       break;
1101 
1102     case FORM_SET_CD_ORDER_ID:
1103       OptionMenu            = (BM_MENU_OPTION *) &LegacyCDMenu;
1104       LegacyDev             = CallbackData->BmmFakeNvData.LegacyCD;
1105       CallbackData->BbsType = BBS_CDROM;
1106       break;
1107 
1108     case FORM_SET_NET_ORDER_ID:
1109       OptionMenu            = (BM_MENU_OPTION *) &LegacyNETMenu;
1110       LegacyDev             = CallbackData->BmmFakeNvData.LegacyNET;
1111       CallbackData->BbsType = BBS_EMBED_NETWORK;
1112       break;
1113 
1114     default:
1115       ASSERT (FORM_SET_BEV_ORDER_ID == CallbackData->BmmPreviousPageId);
1116       OptionMenu            = (BM_MENU_OPTION *) &LegacyBEVMenu;
1117       LegacyDev             = CallbackData->BmmFakeNvData.LegacyBEV;
1118       CallbackData->BbsType = BBS_BEV_DEVICE;
1119       break;
1120   }
1121 
1122   DisMap  = CallbackData->BmmOldFakeNVData.DisableMap;
1123   Status  = EFI_SUCCESS;
1124 
1125 
1126   //
1127   // Update the Variable "LegacyDevOrder"
1128   //
1129   VarData = (UINT8 *) BdsLibGetVariableAndSize (
1130                         VAR_LEGACY_DEV_ORDER,
1131                         &gEfiLegacyDevOrderVariableGuid,
1132                         &VarSize
1133                         );
1134 
1135   if (VarData == NULL) {
1136     return EFI_NOT_FOUND;
1137   }
1138 
1139   OriginalPtr = VarData;
1140   DevOrder    = (LEGACY_DEV_ORDER_ENTRY *) VarData;
1141 
1142   while (VarData < OriginalPtr + VarSize) {
1143     if (DevOrder->BbsType == CallbackData->BbsType) {
1144       break;
1145     }
1146 
1147     VarData += sizeof (BBS_TYPE) + DevOrder->Length;
1148     DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
1149   }
1150 
1151   if (VarData >= OriginalPtr + VarSize) {
1152     FreePool (OriginalPtr);
1153     return EFI_NOT_FOUND;
1154   }
1155 
1156   NewOrder = AllocateZeroPool (DevOrder->Length - sizeof (DevOrder->Length));
1157   if (NewOrder == NULL) {
1158     FreePool (OriginalPtr);
1159     return EFI_OUT_OF_RESOURCES;
1160   }
1161 
1162   for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
1163     if (0xFF == LegacyDev[Index]) {
1164       break;
1165     }
1166 
1167     NewOrder[Index] = LegacyDev[Index];
1168   }
1169   //
1170   // Only the enable/disable state of each boot device with same device type can be changed,
1171   // so we can count on the index information in DevOrder.
1172   // DisMap bit array is the only reliable source to check a device's en/dis state,
1173   // so we use DisMap to set en/dis state of each item in NewOrder array
1174   //
1175   for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) {
1176     Tmp = (UINT16) (DevOrder->Data[Index2] & 0xFF);
1177     Pos = Tmp / 8;
1178     Bit = 7 - (Tmp % 8);
1179     if ((DisMap[Pos] & (1 << Bit)) != 0) {
1180       NewOrder[Index] = (UINT16) (0xFF00 | Tmp);
1181       Index++;
1182     }
1183   }
1184 
1185   CopyMem (
1186     DevOrder->Data,
1187     NewOrder,
1188     DevOrder->Length - sizeof (DevOrder->Length)
1189     );
1190   FreePool (NewOrder);
1191 
1192   Status = gRT->SetVariable (
1193                   VAR_LEGACY_DEV_ORDER,
1194                   &gEfiLegacyDevOrderVariableGuid,
1195                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1196                   VarSize,
1197                   OriginalPtr
1198                   );
1199 
1200 
1201   //
1202   // Update BootOrder and Boot####.Attribute
1203   //
1204   // 1. Re-order the Option Number in BootOrder according to Legacy Dev Order
1205   //
1206   ASSERT (OptionMenu->MenuNumber == DevOrder->Length / sizeof (UINT16) - 1);
1207 
1208   OrderLegacyBootOption4SameType (
1209     DevOrder->Data,
1210     DevOrder->Length / sizeof (UINT16) - 1,
1211     &EnBootOption,
1212     &EnBootOptionCount,
1213     &DisBootOption,
1214     &DisBootOptionCount
1215     );
1216 
1217   //
1218   // 2. Deactivate the DisBootOption and activate the EnBootOption
1219   //
1220   for (Index = 0; Index < DisBootOptionCount; Index++) {
1221     UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", DisBootOption[Index]);
1222     BootOptionVar = BdsLibGetVariableAndSize (
1223                       VarName,
1224                       &gEfiGlobalVariableGuid,
1225                       &OptionSize
1226                       );
1227     if (BootOptionVar != NULL) {
1228       Attribute   = (UINT32 *) BootOptionVar;
1229       *Attribute &= ~LOAD_OPTION_ACTIVE;
1230 
1231       Status = gRT->SetVariable (
1232                       VarName,
1233                       &gEfiGlobalVariableGuid,
1234                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1235                       OptionSize,
1236                       BootOptionVar
1237                       );
1238       //
1239       // Changing the content without increasing its size with current variable implementation shouldn't fail.
1240       //
1241       ASSERT_EFI_ERROR (Status);
1242 
1243       FreePool (BootOptionVar);
1244     }
1245   }
1246 
1247   for (Index = 0; Index < EnBootOptionCount; Index++) {
1248     UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", EnBootOption[Index]);
1249     BootOptionVar = BdsLibGetVariableAndSize (
1250                       VarName,
1251                       &gEfiGlobalVariableGuid,
1252                       &OptionSize
1253                       );
1254     if (BootOptionVar != NULL) {
1255       Attribute   = (UINT32 *) BootOptionVar;
1256       *Attribute |= LOAD_OPTION_ACTIVE;
1257 
1258       Status = gRT->SetVariable (
1259                       VarName,
1260                       &gEfiGlobalVariableGuid,
1261                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1262                       OptionSize,
1263                       BootOptionVar
1264                       );
1265       //
1266       // Changing the content without increasing its size with current variable implementation shouldn't fail.
1267       //
1268       ASSERT_EFI_ERROR (Status);
1269 
1270       FreePool (BootOptionVar);
1271     }
1272   }
1273 
1274   BOpt_GetBootOptions (CallbackData);
1275 
1276   FreePool (OriginalPtr);
1277   FreePool (EnBootOption);
1278   FreePool (DisBootOption);
1279   return Status;
1280 }
1281 
1282 /**
1283   Update the Text Mode of Console.
1284 
1285   @param CallbackData  The context data for BMM.
1286 
1287   @retval EFI_SUCCSS If the Text Mode of Console is updated.
1288   @return Other value if the Text Mode of Console is not updated.
1289 
1290 **/
1291 EFI_STATUS
Var_UpdateConMode(IN BMM_CALLBACK_DATA * CallbackData)1292 Var_UpdateConMode (
1293   IN BMM_CALLBACK_DATA            *CallbackData
1294   )
1295 {
1296   EFI_STATUS        Status;
1297   UINTN             Mode;
1298   CONSOLE_OUT_MODE  ModeInfo;
1299 
1300   Mode = CallbackData->BmmFakeNvData.ConsoleOutMode;
1301 
1302   Status = gST->ConOut->QueryMode (gST->ConOut, Mode, &(ModeInfo.Column), &(ModeInfo.Row));
1303   if (!EFI_ERROR(Status)) {
1304     Status = PcdSet32S (PcdSetupConOutColumn, (UINT32) ModeInfo.Column);
1305     if (!EFI_ERROR (Status)){
1306       Status = PcdSet32S (PcdSetupConOutRow, (UINT32) ModeInfo.Row);
1307     }
1308   }
1309 
1310   return Status;
1311 }
1312