1 /** @file
2   Variable operation that will be used by bootmaint
3 
4 Copyright (c) 2004 - 2015, 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     StrCpyS (DescriptionData, DESCRIPTION_DATA_SIZE, 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     StrCpyS (
767       NvRamMap->BootDescriptionData,
768       sizeof (NvRamMap->BootDescriptionData) / sizeof (NvRamMap->BootDescriptionData[0]),
769       BootString
770       );
771   }
772 
773   BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (NvRamMap->BootDescriptionData);
774   BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
775 
776   if (NvRamMap->BootOptionalData[0] != 0x0000) {
777     OptionalDataExist = TRUE;
778     BufferSize += StrSize (NvRamMap->BootOptionalData);
779   }
780 
781   Buffer = AllocateZeroPool (BufferSize);
782   if (NULL == Buffer) {
783     return EFI_OUT_OF_RESOURCES;
784   }
785 
786   NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
787   if (NULL == NewMenuEntry) {
788     return EFI_OUT_OF_RESOURCES;
789   }
790 
791   NewLoadContext                  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
792   NewLoadContext->Deleted         = FALSE;
793   NewLoadContext->LoadOptionSize  = BufferSize;
794   Ptr = (UINT8 *) Buffer;
795   NewLoadContext->LoadOption = Ptr;
796   *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
797   NewLoadContext->Attributes = *((UINT32 *) Ptr);
798   NewLoadContext->IsActive = TRUE;
799   NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
800 
801   Ptr += sizeof (UINT32);
802   *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
803   NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
804   Ptr += sizeof (UINT16);
805 
806   CopyMem (
807     Ptr,
808     NvRamMap->BootDescriptionData,
809     StrSize (NvRamMap->BootDescriptionData)
810     );
811 
812   NewLoadContext->Description = AllocateZeroPool (StrSize (NvRamMap->BootDescriptionData));
813   ASSERT (NewLoadContext->Description != NULL);
814 
815   NewMenuEntry->DisplayString = NewLoadContext->Description;
816   CopyMem (
817     NewLoadContext->Description,
818     (VOID *) Ptr,
819     StrSize (NvRamMap->BootDescriptionData)
820     );
821 
822   Ptr += StrSize (NvRamMap->BootDescriptionData);
823   CopyMem (
824     Ptr,
825     CallbackData->LoadContext->FilePathList,
826     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
827     );
828 
829   NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
830   ASSERT (NewLoadContext->FilePathList != NULL);
831 
832   CopyMem (
833     NewLoadContext->FilePathList,
834     (VOID *) Ptr,
835     GetDevicePathSize (CallbackData->LoadContext->FilePathList)
836     );
837 
838   NewMenuEntry->HelpString    = DevicePathToStr (NewLoadContext->FilePathList);
839   NewMenuEntry->OptionNumber  = Index;
840   NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
841                                       CallbackData,
842                                       BootOptionStrDepository
843                                       );
844   NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->FeHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
845 
846   NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
847                                     CallbackData,
848                                     BootOptionHelpStrDepository
849                                     );
850   NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->FeHiiHandle, 0, NewMenuEntry->HelpString, NULL);
851 
852   if (OptionalDataExist) {
853     Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
854 
855     CopyMem (Ptr, NvRamMap->BootOptionalData, StrSize (NvRamMap->BootOptionalData));
856   }
857 
858   Status = gRT->SetVariable (
859                   BootString,
860                   &gEfiGlobalVariableGuid,
861                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
862                   BufferSize,
863                   Buffer
864                   );
865   if (!EFI_ERROR (Status)) {
866 
867     BootOrderList = BdsLibGetVariableAndSize (
868                       L"BootOrder",
869                       &gEfiGlobalVariableGuid,
870                       &BootOrderListSize
871                       );
872     ASSERT (BootOrderList != NULL);
873     NewBootOrderList = AllocateZeroPool (BootOrderListSize + sizeof (UINT16));
874     ASSERT (NewBootOrderList != NULL);
875     CopyMem (NewBootOrderList, BootOrderList, BootOrderListSize);
876     NewBootOrderList[BootOrderListSize / sizeof (UINT16)] = Index;
877 
878     if (BootOrderList != NULL) {
879       FreePool (BootOrderList);
880     }
881 
882     Status = gRT->SetVariable (
883                     L"BootOrder",
884                     &gEfiGlobalVariableGuid,
885                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
886                     BootOrderListSize + sizeof (UINT16),
887                     NewBootOrderList
888                     );
889     if (!EFI_ERROR (Status)) {
890 
891       FreePool (NewBootOrderList);
892       NewBootOrderList = NULL;
893       InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
894       BootOptionMenu.MenuNumber++;
895 
896       //
897       // Update "change driver order" page used data, append the new add driver
898       // option at the end.
899       //
900       Index = 0;
901       while (CallbackData->BmmFakeNvData.BootOptionOrder[Index] != 0) {
902         Index++;
903       }
904       CallbackData->BmmFakeNvData.BootOptionOrder[Index] = (UINT32) (NewMenuEntry->OptionNumber + 1);
905 
906       NvRamMap->BootDescriptionData[0]  = 0x0000;
907       NvRamMap->BootOptionalData[0]     = 0x0000;
908     }
909   }
910   return EFI_SUCCESS;
911 }
912 
913 /**
914   This function update the "BootNext" EFI Variable. If there is
915   no "BootNext" specified in BMM, this EFI Variable is deleted.
916   It also update the BMM context data specified the "BootNext"
917   vaule.
918 
919   @param CallbackData    The BMM context data.
920 
921   @retval EFI_SUCCESS    The function complete successfully.
922   @return                The EFI variable can be saved. See gRT->SetVariable
923                          for detail return information.
924 
925 **/
926 EFI_STATUS
Var_UpdateBootNext(IN BMM_CALLBACK_DATA * CallbackData)927 Var_UpdateBootNext (
928   IN BMM_CALLBACK_DATA            *CallbackData
929   )
930 {
931   BM_MENU_ENTRY     *NewMenuEntry;
932   BM_LOAD_CONTEXT   *NewLoadContext;
933   BMM_FAKE_NV_DATA  *CurrentFakeNVMap;
934   UINT16            Index;
935   EFI_STATUS        Status;
936 
937   Status            = EFI_SUCCESS;
938   CurrentFakeNVMap  = &CallbackData->BmmFakeNvData;
939   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
940     NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
941     ASSERT (NULL != NewMenuEntry);
942 
943     NewLoadContext              = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
944     NewLoadContext->IsBootNext  = FALSE;
945   }
946 
947   if (CurrentFakeNVMap->BootNext == BootOptionMenu.MenuNumber) {
948     EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
949     return EFI_SUCCESS;
950   }
951 
952   NewMenuEntry = BOpt_GetMenuEntry (
953                   &BootOptionMenu,
954                   CurrentFakeNVMap->BootNext
955                   );
956   ASSERT (NewMenuEntry != NULL);
957 
958   NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
959   Status = gRT->SetVariable (
960                   L"BootNext",
961                   &gEfiGlobalVariableGuid,
962                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
963                   sizeof (UINT16),
964                   &NewMenuEntry->OptionNumber
965                   );
966   NewLoadContext->IsBootNext              = TRUE;
967   CallbackData->BmmOldFakeNVData.BootNext = CurrentFakeNVMap->BootNext;
968   return Status;
969 }
970 
971 /**
972   This function update the "BootOrder" EFI Variable based on
973   BMM Formset's NV map. It then refresh BootOptionMenu
974   with the new "BootOrder" list.
975 
976   @param CallbackData    The BMM context data.
977 
978   @retval EFI_SUCCESS             The function complete successfully.
979   @retval EFI_OUT_OF_RESOURCES    Not enough memory to complete the function.
980   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
981 
982 **/
983 EFI_STATUS
Var_UpdateBootOrder(IN BMM_CALLBACK_DATA * CallbackData)984 Var_UpdateBootOrder (
985   IN BMM_CALLBACK_DATA            *CallbackData
986   )
987 {
988   EFI_STATUS  Status;
989   UINT16      Index;
990   UINT16      OrderIndex;
991   UINT16      *BootOrderList;
992   UINTN       BootOrderListSize;
993   UINT16      OptionNumber;
994 
995   BootOrderList     = NULL;
996   BootOrderListSize = 0;
997 
998   //
999   // First check whether BootOrder is present in current configuration
1000   //
1001   BootOrderList = BdsLibGetVariableAndSize (
1002                     L"BootOrder",
1003                     &gEfiGlobalVariableGuid,
1004                     &BootOrderListSize
1005                     );
1006   if (BootOrderList == NULL) {
1007     return EFI_OUT_OF_RESOURCES;
1008   }
1009 
1010   ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.BootOptionOrder) / sizeof (CallbackData->BmmFakeNvData.BootOptionOrder[0])));
1011 
1012   for (OrderIndex = 0; (OrderIndex < BootOptionMenu.MenuNumber) && (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] != 0); OrderIndex++) {
1013     for (Index = OrderIndex; Index < BootOrderListSize / sizeof (UINT16); Index++) {
1014       if ((BootOrderList[Index] == (UINT16) (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] - 1)) && (OrderIndex != Index)) {
1015         OptionNumber = BootOrderList[Index];
1016         CopyMem (&BootOrderList[OrderIndex + 1], &BootOrderList[OrderIndex], (Index - OrderIndex) * sizeof (UINT16));
1017         BootOrderList[OrderIndex] = OptionNumber;
1018       }
1019     }
1020   }
1021 
1022   Status = gRT->SetVariable (
1023                   L"BootOrder",
1024                   &gEfiGlobalVariableGuid,
1025                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1026                   BootOrderListSize,
1027                   BootOrderList
1028                   );
1029   //
1030   // Changing the content without increasing its size with current variable implementation shouldn't fail.
1031   //
1032   ASSERT_EFI_ERROR (Status);
1033   FreePool (BootOrderList);
1034 
1035   GroupMultipleLegacyBootOption4SameType ();
1036 
1037   BOpt_FreeMenu (&BootOptionMenu);
1038   BOpt_GetBootOptions (CallbackData);
1039 
1040   return Status;
1041 
1042 }
1043 
1044 /**
1045   This function update the "DriverOrder" EFI Variable based on
1046   BMM Formset's NV map. It then refresh DriverOptionMenu
1047   with the new "DriverOrder" list.
1048 
1049   @param CallbackData    The BMM context data.
1050 
1051   @retval EFI_SUCCESS           The function complete successfully.
1052   @retval EFI_OUT_OF_RESOURCES  Not enough memory to complete the function.
1053   @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
1054 
1055 **/
1056 EFI_STATUS
Var_UpdateDriverOrder(IN BMM_CALLBACK_DATA * CallbackData)1057 Var_UpdateDriverOrder (
1058   IN BMM_CALLBACK_DATA            *CallbackData
1059   )
1060 {
1061   EFI_STATUS  Status;
1062   UINT16      Index;
1063   UINT16      *DriverOrderList;
1064   UINT16      *NewDriverOrderList;
1065   UINTN       DriverOrderListSize;
1066 
1067   DriverOrderList     = NULL;
1068   DriverOrderListSize = 0;
1069 
1070   //
1071   // First check whether DriverOrder is present in current configuration
1072   //
1073   DriverOrderList = BdsLibGetVariableAndSize (
1074                       L"DriverOrder",
1075                       &gEfiGlobalVariableGuid,
1076                       &DriverOrderListSize
1077                       );
1078 
1079   NewDriverOrderList = AllocateZeroPool (DriverOrderListSize);
1080 
1081   if (NewDriverOrderList == NULL) {
1082     return EFI_OUT_OF_RESOURCES;
1083   }
1084   //
1085   // If exists, delete it to hold new DriverOrder
1086   //
1087   if (DriverOrderList != NULL) {
1088     EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
1089     FreePool (DriverOrderList);
1090   }
1091 
1092   ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder) / sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder[0])));
1093   for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
1094     NewDriverOrderList[Index] = (UINT16) (CallbackData->BmmFakeNvData.DriverOptionOrder[Index] - 1);
1095   }
1096 
1097   Status = gRT->SetVariable (
1098                   L"DriverOrder",
1099                   &gEfiGlobalVariableGuid,
1100                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1101                   DriverOrderListSize,
1102                   NewDriverOrderList
1103                   );
1104   //
1105   // Changing the content without increasing its size with current variable implementation shouldn't fail.
1106   //
1107   ASSERT_EFI_ERROR (Status);
1108 
1109   BOpt_FreeMenu (&DriverOptionMenu);
1110   BOpt_GetDriverOptions (CallbackData);
1111   return EFI_SUCCESS;
1112 }
1113 
1114 /**
1115   Update the legacy BBS boot option. VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable
1116   is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid
1117   is also updated.
1118 
1119   @param CallbackData    The context data for BMM.
1120   @param FormId          The form id.
1121 
1122   @return EFI_SUCCESS           The function completed successfully.
1123   @retval EFI_NOT_FOUND         If VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable can be found.
1124   @retval EFI_OUT_OF_RESOURCES  Fail to allocate memory resource
1125 **/
1126 EFI_STATUS
Var_UpdateBBSOption(IN BMM_CALLBACK_DATA * CallbackData,IN EFI_FORM_ID FormId)1127 Var_UpdateBBSOption (
1128   IN BMM_CALLBACK_DATA            *CallbackData,
1129   IN EFI_FORM_ID                  FormId
1130   )
1131 {
1132   UINTN                       Index;
1133   UINTN                       Index2;
1134   VOID                        *BootOptionVar;
1135   CHAR16                      VarName[100];
1136   UINTN                       OptionSize;
1137   EFI_STATUS                  Status;
1138   UINT32                      *Attribute;
1139   BM_MENU_OPTION              *OptionMenu;
1140   UINT8                       *LegacyDev;
1141   UINT8                       *VarData;
1142   UINTN                       VarSize;
1143   LEGACY_DEV_ORDER_ENTRY      *DevOrder;
1144   UINT8                       *OriginalPtr;
1145   UINT8                       *DisMap;
1146   UINTN                       Pos;
1147   UINTN                       Bit;
1148   UINT16                      *NewOrder;
1149   UINT16                      Tmp;
1150   UINT16                      *EnBootOption;
1151   UINTN                       EnBootOptionCount;
1152   UINT16                      *DisBootOption;
1153   UINTN                       DisBootOptionCount;
1154 
1155   DisMap              = NULL;
1156   NewOrder            = NULL;
1157 
1158   switch (FormId) {
1159     case FORM_SET_FD_ORDER_ID:
1160       OptionMenu            = (BM_MENU_OPTION *) &LegacyFDMenu;
1161       LegacyDev             = CallbackData->BmmFakeNvData.LegacyFD;
1162       CallbackData->BbsType = BBS_FLOPPY;
1163       break;
1164 
1165     case FORM_SET_HD_ORDER_ID:
1166       OptionMenu            = (BM_MENU_OPTION *) &LegacyHDMenu;
1167       LegacyDev             = CallbackData->BmmFakeNvData.LegacyHD;
1168       CallbackData->BbsType = BBS_HARDDISK;
1169       break;
1170 
1171     case FORM_SET_CD_ORDER_ID:
1172       OptionMenu            = (BM_MENU_OPTION *) &LegacyCDMenu;
1173       LegacyDev             = CallbackData->BmmFakeNvData.LegacyCD;
1174       CallbackData->BbsType = BBS_CDROM;
1175       break;
1176 
1177     case FORM_SET_NET_ORDER_ID:
1178       OptionMenu            = (BM_MENU_OPTION *) &LegacyNETMenu;
1179       LegacyDev             = CallbackData->BmmFakeNvData.LegacyNET;
1180       CallbackData->BbsType = BBS_EMBED_NETWORK;
1181       break;
1182 
1183     default:
1184       ASSERT (FORM_SET_BEV_ORDER_ID == CallbackData->BmmPreviousPageId);
1185       OptionMenu            = (BM_MENU_OPTION *) &LegacyBEVMenu;
1186       LegacyDev             = CallbackData->BmmFakeNvData.LegacyBEV;
1187       CallbackData->BbsType = BBS_BEV_DEVICE;
1188       break;
1189   }
1190 
1191   DisMap  = CallbackData->BmmOldFakeNVData.DisableMap;
1192   Status  = EFI_SUCCESS;
1193 
1194 
1195   //
1196   // Update the Variable "LegacyDevOrder"
1197   //
1198   VarData = (UINT8 *) BdsLibGetVariableAndSize (
1199                         VAR_LEGACY_DEV_ORDER,
1200                         &gEfiLegacyDevOrderVariableGuid,
1201                         &VarSize
1202                         );
1203 
1204   if (VarData == NULL) {
1205     return EFI_NOT_FOUND;
1206   }
1207 
1208   OriginalPtr = VarData;
1209   DevOrder    = (LEGACY_DEV_ORDER_ENTRY *) VarData;
1210 
1211   while (VarData < OriginalPtr + VarSize) {
1212     if (DevOrder->BbsType == CallbackData->BbsType) {
1213       break;
1214     }
1215 
1216     VarData += sizeof (BBS_TYPE) + DevOrder->Length;
1217     DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
1218   }
1219 
1220   if (VarData >= OriginalPtr + VarSize) {
1221     FreePool (OriginalPtr);
1222     return EFI_NOT_FOUND;
1223   }
1224 
1225   NewOrder = AllocateZeroPool (DevOrder->Length - sizeof (DevOrder->Length));
1226   if (NewOrder == NULL) {
1227     FreePool (OriginalPtr);
1228     return EFI_OUT_OF_RESOURCES;
1229   }
1230 
1231   for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
1232     if (0xFF == LegacyDev[Index]) {
1233       break;
1234     }
1235 
1236     NewOrder[Index] = LegacyDev[Index];
1237   }
1238   //
1239   // Only the enable/disable state of each boot device with same device type can be changed,
1240   // so we can count on the index information in DevOrder.
1241   // DisMap bit array is the only reliable source to check a device's en/dis state,
1242   // so we use DisMap to set en/dis state of each item in NewOrder array
1243   //
1244   for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) {
1245     Tmp = (UINT16) (DevOrder->Data[Index2] & 0xFF);
1246     Pos = Tmp / 8;
1247     Bit = 7 - (Tmp % 8);
1248     if ((DisMap[Pos] & (1 << Bit)) != 0) {
1249       NewOrder[Index] = (UINT16) (0xFF00 | Tmp);
1250       Index++;
1251     }
1252   }
1253 
1254   CopyMem (
1255     DevOrder->Data,
1256     NewOrder,
1257     DevOrder->Length - sizeof (DevOrder->Length)
1258     );
1259   FreePool (NewOrder);
1260 
1261   Status = gRT->SetVariable (
1262                   VAR_LEGACY_DEV_ORDER,
1263                   &gEfiLegacyDevOrderVariableGuid,
1264                   EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1265                   VarSize,
1266                   OriginalPtr
1267                   );
1268 
1269 
1270   //
1271   // Update BootOrder and Boot####.Attribute
1272   //
1273   // 1. Re-order the Option Number in BootOrder according to Legacy Dev Order
1274   //
1275   ASSERT (OptionMenu->MenuNumber == DevOrder->Length / sizeof (UINT16) - 1);
1276 
1277   OrderLegacyBootOption4SameType (
1278     DevOrder->Data,
1279     DevOrder->Length / sizeof (UINT16) - 1,
1280     &EnBootOption,
1281     &EnBootOptionCount,
1282     &DisBootOption,
1283     &DisBootOptionCount
1284     );
1285 
1286   //
1287   // 2. Deactivate the DisBootOption and activate the EnBootOption
1288   //
1289   for (Index = 0; Index < DisBootOptionCount; Index++) {
1290     UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", DisBootOption[Index]);
1291     BootOptionVar = BdsLibGetVariableAndSize (
1292                       VarName,
1293                       &gEfiGlobalVariableGuid,
1294                       &OptionSize
1295                       );
1296     if (BootOptionVar != NULL) {
1297       Attribute   = (UINT32 *) BootOptionVar;
1298       *Attribute &= ~LOAD_OPTION_ACTIVE;
1299 
1300       Status = gRT->SetVariable (
1301                       VarName,
1302                       &gEfiGlobalVariableGuid,
1303                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1304                       OptionSize,
1305                       BootOptionVar
1306                       );
1307       //
1308       // Changing the content without increasing its size with current variable implementation shouldn't fail.
1309       //
1310       ASSERT_EFI_ERROR (Status);
1311 
1312       FreePool (BootOptionVar);
1313     }
1314   }
1315 
1316   for (Index = 0; Index < EnBootOptionCount; Index++) {
1317     UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", EnBootOption[Index]);
1318     BootOptionVar = BdsLibGetVariableAndSize (
1319                       VarName,
1320                       &gEfiGlobalVariableGuid,
1321                       &OptionSize
1322                       );
1323     if (BootOptionVar != NULL) {
1324       Attribute   = (UINT32 *) BootOptionVar;
1325       *Attribute |= LOAD_OPTION_ACTIVE;
1326 
1327       Status = gRT->SetVariable (
1328                       VarName,
1329                       &gEfiGlobalVariableGuid,
1330                       EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1331                       OptionSize,
1332                       BootOptionVar
1333                       );
1334       //
1335       // Changing the content without increasing its size with current variable implementation shouldn't fail.
1336       //
1337       ASSERT_EFI_ERROR (Status);
1338 
1339       FreePool (BootOptionVar);
1340     }
1341   }
1342 
1343   BOpt_GetBootOptions (CallbackData);
1344 
1345   FreePool (OriginalPtr);
1346   FreePool (EnBootOption);
1347   FreePool (DisBootOption);
1348   return Status;
1349 }
1350 
1351 /**
1352   Update the Text Mode of Console.
1353 
1354   @param CallbackData  The context data for BMM.
1355 
1356   @retval EFI_SUCCSS If the Text Mode of Console is updated.
1357   @return Other value if the Text Mode of Console is not updated.
1358 
1359 **/
1360 EFI_STATUS
Var_UpdateConMode(IN BMM_CALLBACK_DATA * CallbackData)1361 Var_UpdateConMode (
1362   IN BMM_CALLBACK_DATA            *CallbackData
1363   )
1364 {
1365   EFI_STATUS        Status;
1366   UINTN             Mode;
1367   CONSOLE_OUT_MODE  ModeInfo;
1368 
1369   Mode = CallbackData->BmmFakeNvData.ConsoleOutMode;
1370 
1371   Status = gST->ConOut->QueryMode (gST->ConOut, Mode, &(ModeInfo.Column), &(ModeInfo.Row));
1372   if (!EFI_ERROR(Status)) {
1373     Status = PcdSet32S (PcdSetupConOutColumn, (UINT32) ModeInfo.Column);
1374     if (!EFI_ERROR (Status)){
1375       Status = PcdSet32S (PcdSetupConOutRow, (UINT32) ModeInfo.Row);
1376     }
1377   }
1378 
1379   return Status;
1380 }
1381