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