1/** @file
2  Variable operation that will be used by bootmaint
3
4Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT 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**/
28EFI_STATUS
29Var_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**/
96EFI_STATUS
97Var_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**/
187EFI_STATUS
188Var_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**/
244EFI_STATUS
245Var_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**/
321VOID
322Var_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**/
402EFI_STATUS
403Var_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**/
495EFI_STATUS
496Var_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**/
510EFI_STATUS
511Var_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**/
525EFI_STATUS
526Var_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**/
549EFI_STATUS
550Var_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**/
741EFI_STATUS
742Var_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**/
926EFI_STATUS
927Var_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**/
983EFI_STATUS
984Var_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**/
1056EFI_STATUS
1057Var_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**/
1126EFI_STATUS
1127Var_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**/
1360EFI_STATUS
1361Var_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