Home | History | Annotate | Download | only in BootMaintenanceManagerUiLib
      1 /** @file
      2 The functions for Boot Maintainence Main menu.
      3 
      4 Copyright (c) 2004 - 2016, 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 "BootMaintenanceManager.h"
     16 
     17 #define FRONT_PAGE_KEY_OFFSET          0x4000
     18 //
     19 // Boot video resolution and text mode.
     20 //
     21 UINT32    mBmmBootHorizontalResolution    = 0;
     22 UINT32    mBmmBootVerticalResolution      = 0;
     23 UINT32    mBmmBootTextModeColumn          = 0;
     24 UINT32    mBmmBootTextModeRow             = 0;
     25 //
     26 // BIOS setup video resolution and text mode.
     27 //
     28 UINT32    mBmmSetupTextModeColumn         = 0;
     29 UINT32    mBmmSetupTextModeRow            = 0;
     30 UINT32    mBmmSetupHorizontalResolution   = 0;
     31 UINT32    mBmmSetupVerticalResolution     = 0;
     32 
     33 BOOLEAN   mBmmModeInitialized             = FALSE;
     34 
     35 EFI_DEVICE_PATH_PROTOCOL  EndDevicePath[] = {
     36   {
     37     END_DEVICE_PATH_TYPE,
     38     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     39     {
     40       END_DEVICE_PATH_LENGTH,
     41       0
     42     }
     43   }
     44 };
     45 
     46 HII_VENDOR_DEVICE_PATH  mBmmHiiVendorDevicePath = {
     47   {
     48     {
     49       HARDWARE_DEVICE_PATH,
     50       HW_VENDOR_DP,
     51       {
     52         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
     53         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
     54       }
     55     },
     56     //
     57     // {165A028F-0BB2-4b5f-8747-77592E3F6499}
     58     //
     59     { 0x165a028f, 0xbb2, 0x4b5f, { 0x87, 0x47, 0x77, 0x59, 0x2e, 0x3f, 0x64, 0x99 } }
     60   },
     61   {
     62     END_DEVICE_PATH_TYPE,
     63     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     64     {
     65       (UINT8) (END_DEVICE_PATH_LENGTH),
     66       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
     67     }
     68   }
     69 };
     70 
     71 EFI_GUID mBootMaintGuid          = BOOT_MAINT_FORMSET_GUID;
     72 
     73 CHAR16  mBootMaintStorageName[]     = L"BmmData";
     74 BMM_CALLBACK_DATA  gBootMaintenancePrivate = {
     75   BMM_CALLBACK_DATA_SIGNATURE,
     76   NULL,
     77   NULL,
     78   {
     79     BootMaintExtractConfig,
     80     BootMaintRouteConfig,
     81     BootMaintCallback
     82   }
     83 };
     84 
     85 BMM_CALLBACK_DATA *mBmmCallbackInfo = &gBootMaintenancePrivate;
     86 BOOLEAN  mAllMenuInit               = FALSE;
     87 BOOLEAN  mFirstEnterBMMForm         = FALSE;
     88 
     89 /**
     90   Init all memu.
     91 
     92   @param CallbackData    The BMM context data.
     93 
     94 **/
     95 VOID
     96 InitAllMenu (
     97   IN  BMM_CALLBACK_DATA    *CallbackData
     98   );
     99 
    100 /**
    101   Free up all Menu Option list.
    102 
    103 **/
    104 VOID
    105 FreeAllMenu (
    106   VOID
    107   );
    108 
    109 /**
    110 
    111   Update the menus in the BMM page.
    112 
    113 **/
    114 VOID
    115 CustomizeMenus (
    116   VOID
    117   );
    118 
    119 /**
    120   This function will change video resolution and text mode
    121   according to defined setup mode or defined boot mode
    122 
    123   @param  IsSetupMode   Indicate mode is changed to setup mode or boot mode.
    124 
    125   @retval  EFI_SUCCESS  Mode is changed successfully.
    126   @retval  Others       Mode failed to be changed.
    127 
    128 **/
    129 EFI_STATUS
    130 BmmSetConsoleMode (
    131   BOOLEAN  IsSetupMode
    132   )
    133 {
    134   EFI_GRAPHICS_OUTPUT_PROTOCOL          *GraphicsOutput;
    135   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL       *SimpleTextOut;
    136   UINTN                                 SizeOfInfo;
    137   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
    138   UINT32                                MaxGopMode;
    139   UINT32                                MaxTextMode;
    140   UINT32                                ModeNumber;
    141   UINT32                                NewHorizontalResolution;
    142   UINT32                                NewVerticalResolution;
    143   UINT32                                NewColumns;
    144   UINT32                                NewRows;
    145   UINTN                                 HandleCount;
    146   EFI_HANDLE                            *HandleBuffer;
    147   EFI_STATUS                            Status;
    148   UINTN                                 Index;
    149   UINTN                                 CurrentColumn;
    150   UINTN                                 CurrentRow;
    151 
    152   MaxGopMode  = 0;
    153   MaxTextMode = 0;
    154 
    155   //
    156   // Get current video resolution and text mode
    157   //
    158   Status = gBS->HandleProtocol (
    159                   gST->ConsoleOutHandle,
    160                   &gEfiGraphicsOutputProtocolGuid,
    161                   (VOID**)&GraphicsOutput
    162                   );
    163   if (EFI_ERROR (Status)) {
    164     GraphicsOutput = NULL;
    165   }
    166 
    167   Status = gBS->HandleProtocol (
    168                   gST->ConsoleOutHandle,
    169                   &gEfiSimpleTextOutProtocolGuid,
    170                   (VOID**)&SimpleTextOut
    171                   );
    172   if (EFI_ERROR (Status)) {
    173     SimpleTextOut = NULL;
    174   }
    175 
    176   if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
    177     return EFI_UNSUPPORTED;
    178   }
    179 
    180   if (IsSetupMode) {
    181     //
    182     // The required resolution and text mode is setup mode.
    183     //
    184     NewHorizontalResolution = mBmmSetupHorizontalResolution;
    185     NewVerticalResolution   = mBmmSetupVerticalResolution;
    186     NewColumns              = mBmmSetupTextModeColumn;
    187     NewRows                 = mBmmSetupTextModeRow;
    188   } else {
    189     //
    190     // The required resolution and text mode is boot mode.
    191     //
    192     NewHorizontalResolution = mBmmBootHorizontalResolution;
    193     NewVerticalResolution   = mBmmBootVerticalResolution;
    194     NewColumns              = mBmmBootTextModeColumn;
    195     NewRows                 = mBmmBootTextModeRow;
    196   }
    197 
    198   if (GraphicsOutput != NULL) {
    199     MaxGopMode  = GraphicsOutput->Mode->MaxMode;
    200   }
    201 
    202   if (SimpleTextOut != NULL) {
    203     MaxTextMode = SimpleTextOut->Mode->MaxMode;
    204   }
    205 
    206   //
    207   // 1. If current video resolution is same with required video resolution,
    208   //    video resolution need not be changed.
    209   //    1.1. If current text mode is same with required text mode, text mode need not be changed.
    210   //    1.2. If current text mode is different from required text mode, text mode need be changed.
    211   // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.
    212   //
    213   for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
    214     Status = GraphicsOutput->QueryMode (
    215                        GraphicsOutput,
    216                        ModeNumber,
    217                        &SizeOfInfo,
    218                        &Info
    219                        );
    220     if (!EFI_ERROR (Status)) {
    221       if ((Info->HorizontalResolution == NewHorizontalResolution) &&
    222           (Info->VerticalResolution == NewVerticalResolution)) {
    223         if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&
    224             (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {
    225           //
    226           // Current resolution is same with required resolution, check if text mode need be set
    227           //
    228           Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
    229           ASSERT_EFI_ERROR (Status);
    230           if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
    231             //
    232             // If current text mode is same with required text mode. Do nothing
    233             //
    234             FreePool (Info);
    235             return EFI_SUCCESS;
    236           } else {
    237             //
    238             // If current text mode is different from required text mode.  Set new video mode
    239             //
    240             for (Index = 0; Index < MaxTextMode; Index++) {
    241               Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
    242               if (!EFI_ERROR(Status)) {
    243                 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
    244                   //
    245                   // Required text mode is supported, set it.
    246                   //
    247                   Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
    248                   ASSERT_EFI_ERROR (Status);
    249                   //
    250                   // Update text mode PCD.
    251                   //
    252                   Status = PcdSet32S (PcdConOutColumn, mBmmSetupTextModeColumn);
    253                   ASSERT_EFI_ERROR (Status);
    254                   Status = PcdSet32S (PcdConOutRow, mBmmSetupTextModeRow);
    255                   ASSERT_EFI_ERROR (Status);
    256                   FreePool (Info);
    257                   return EFI_SUCCESS;
    258                 }
    259               }
    260             }
    261             if (Index == MaxTextMode) {
    262               //
    263               // If required text mode is not supported, return error.
    264               //
    265               FreePool (Info);
    266               return EFI_UNSUPPORTED;
    267             }
    268           }
    269         } else {
    270           //
    271           // If current video resolution is not same with the new one, set new video resolution.
    272           // In this case, the driver which produces simple text out need be restarted.
    273           //
    274           Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
    275           if (!EFI_ERROR (Status)) {
    276             FreePool (Info);
    277             break;
    278           }
    279         }
    280       }
    281       FreePool (Info);
    282     }
    283   }
    284 
    285   if (ModeNumber == MaxGopMode) {
    286     //
    287     // If the resolution is not supported, return error.
    288     //
    289     return EFI_UNSUPPORTED;
    290   }
    291 
    292   //
    293   // Set PCD to Inform GraphicsConsole to change video resolution.
    294   // Set PCD to Inform Consplitter to change text mode.
    295   //
    296   Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);
    297   ASSERT_EFI_ERROR (Status);
    298   Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);
    299   ASSERT_EFI_ERROR (Status);
    300   Status = PcdSet32S (PcdConOutColumn, NewColumns);
    301   ASSERT_EFI_ERROR (Status);
    302   Status = PcdSet32S (PcdConOutRow, NewRows);
    303   ASSERT_EFI_ERROR (Status);
    304 
    305   //
    306   // Video mode is changed, so restart graphics console driver and higher level driver.
    307   // Reconnect graphics console driver and higher level driver.
    308   // Locate all the handles with GOP protocol and reconnect it.
    309   //
    310   Status = gBS->LocateHandleBuffer (
    311                    ByProtocol,
    312                    &gEfiSimpleTextOutProtocolGuid,
    313                    NULL,
    314                    &HandleCount,
    315                    &HandleBuffer
    316                    );
    317   if (!EFI_ERROR (Status)) {
    318     for (Index = 0; Index < HandleCount; Index++) {
    319       gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
    320     }
    321     for (Index = 0; Index < HandleCount; Index++) {
    322       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
    323     }
    324     if (HandleBuffer != NULL) {
    325       FreePool (HandleBuffer);
    326     }
    327   }
    328 
    329   return EFI_SUCCESS;
    330 }
    331 
    332 /**
    333   This function converts an input device structure to a Unicode string.
    334 
    335   @param DevPath      A pointer to the device path structure.
    336 
    337   @return             A new allocated Unicode string that represents the device path.
    338 
    339 **/
    340 CHAR16 *
    341 UiDevicePathToStr (
    342   IN EFI_DEVICE_PATH_PROTOCOL     *DevPath
    343   )
    344 {
    345   EFI_STATUS                       Status;
    346   CHAR16                           *ToText;
    347   EFI_DEVICE_PATH_TO_TEXT_PROTOCOL *DevPathToText;
    348 
    349   if (DevPath == NULL) {
    350     return NULL;
    351   }
    352 
    353   Status = gBS->LocateProtocol (
    354                   &gEfiDevicePathToTextProtocolGuid,
    355                   NULL,
    356                   (VOID **) &DevPathToText
    357                   );
    358   ASSERT_EFI_ERROR (Status);
    359   ToText = DevPathToText->ConvertDevicePathToText (
    360                             DevPath,
    361                             FALSE,
    362                             TRUE
    363                             );
    364   ASSERT (ToText != NULL);
    365   return ToText;
    366 }
    367 
    368 /**
    369   Extract filename from device path. The returned buffer is allocated using AllocateCopyPool.
    370   The caller is responsible for freeing the allocated buffer using FreePool().
    371 
    372   @param DevicePath       Device path.
    373 
    374   @return                 A new allocated string that represents the file name.
    375 
    376 **/
    377 CHAR16 *
    378 ExtractFileNameFromDevicePath (
    379   IN   EFI_DEVICE_PATH_PROTOCOL *DevicePath
    380   )
    381 {
    382   CHAR16          *String;
    383   CHAR16          *MatchString;
    384   CHAR16          *LastMatch;
    385   CHAR16          *FileName;
    386   UINTN           Length;
    387 
    388   ASSERT(DevicePath != NULL);
    389 
    390   String = UiDevicePathToStr(DevicePath);
    391   MatchString = String;
    392   LastMatch   = String;
    393   FileName    = NULL;
    394 
    395   while(MatchString != NULL){
    396     LastMatch   = MatchString + 1;
    397     MatchString = StrStr(LastMatch,L"\\");
    398   }
    399 
    400   Length = StrLen(LastMatch);
    401   FileName = AllocateCopyPool ((Length + 1) * sizeof(CHAR16), LastMatch);
    402   if (FileName != NULL) {
    403     *(FileName + Length) = 0;
    404   }
    405 
    406   FreePool(String);
    407 
    408   return FileName;
    409 }
    410 
    411 /**
    412   Extract device path for given HII handle and class guid.
    413 
    414   @param Handle          The HII handle.
    415 
    416   @retval  NULL          Fail to get the device path string.
    417   @return  PathString    Get the device path string.
    418 
    419 **/
    420 CHAR16 *
    421 BmmExtractDevicePathFromHiiHandle (
    422   IN      EFI_HII_HANDLE      Handle
    423   )
    424 {
    425   EFI_STATUS                       Status;
    426   EFI_HANDLE                       DriverHandle;
    427 
    428   ASSERT (Handle != NULL);
    429 
    430   if (Handle == NULL) {
    431     return NULL;
    432   }
    433 
    434   Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
    435   if (EFI_ERROR (Status)) {
    436     return NULL;
    437   }
    438 
    439   //
    440   // Get device path string.
    441   //
    442   return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE);
    443 
    444 }
    445 
    446 /**
    447   Converts the unicode character of the string from uppercase to lowercase.
    448   This is a internal function.
    449 
    450   @param ConfigString  String to be converted
    451 
    452 **/
    453 VOID
    454 HiiToLower (
    455   IN EFI_STRING  ConfigString
    456   )
    457 {
    458   EFI_STRING  String;
    459   BOOLEAN     Lower;
    460 
    461   ASSERT (ConfigString != NULL);
    462 
    463   //
    464   // Convert all hex digits in range [A-F] in the configuration header to [a-f]
    465   //
    466   for (String = ConfigString, Lower = FALSE; *String != L'\0'; String++) {
    467     if (*String == L'=') {
    468       Lower = TRUE;
    469     } else if (*String == L'&') {
    470       Lower = FALSE;
    471     } else if (Lower && *String >= L'A' && *String <= L'F') {
    472       *String = (CHAR16) (*String - L'A' + L'a');
    473     }
    474   }
    475 }
    476 
    477 /**
    478   Update the progress string through the offset value.
    479 
    480   @param Offset           The offset value
    481   @param Configuration    Point to the configuration string.
    482 
    483 **/
    484 EFI_STRING
    485 UpdateProgress(
    486   IN  UINTN       Offset,
    487   IN  EFI_STRING  Configuration
    488 )
    489 {
    490   UINTN       Length;
    491   EFI_STRING  StringPtr;
    492   EFI_STRING  ReturnString;
    493 
    494   StringPtr    = NULL;
    495   ReturnString = NULL;
    496 
    497   //
    498   // &OFFSET=XXXX followed by a Null-terminator.
    499   // Length = StrLen (L"&OFFSET=") + 4 + 1
    500   //
    501   Length    = StrLen (L"&OFFSET=") + 4 + 1;
    502 
    503   StringPtr = AllocateZeroPool (Length * sizeof (CHAR16));
    504 
    505   if (StringPtr == NULL) {
    506     return  NULL;
    507   }
    508 
    509   UnicodeSPrint (
    510     StringPtr,
    511     (8 + 4 + 1) * sizeof (CHAR16),
    512     L"&OFFSET=%04x",
    513     Offset
    514     );
    515 
    516   ReturnString = StrStr (Configuration, StringPtr);
    517 
    518   if (ReturnString == NULL) {
    519     //
    520     // If doesn't find the string in Configuration, convert the string to lower case then search again.
    521     //
    522     HiiToLower (StringPtr);
    523     ReturnString = StrStr (Configuration, StringPtr);
    524   }
    525 
    526   FreePool (StringPtr);
    527 
    528   return ReturnString;
    529 }
    530 
    531 /**
    532   Update the terminal content in TerminalMenu.
    533 
    534   @param BmmData           The BMM fake NV data.
    535 
    536 **/
    537 VOID
    538 UpdateTerminalContent (
    539   IN BMM_FAKE_NV_DATA       *BmmData
    540   )
    541 {
    542   UINT16                          Index;
    543   BM_TERMINAL_CONTEXT             *NewTerminalContext;
    544   BM_MENU_ENTRY                   *NewMenuEntry;
    545 
    546   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
    547     NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
    548     ASSERT (NewMenuEntry != NULL);
    549     NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
    550     NewTerminalContext->BaudRateIndex = BmmData->COMBaudRate[Index];
    551     ASSERT (BmmData->COMBaudRate[Index] < (ARRAY_SIZE (BaudRateList)));
    552     NewTerminalContext->BaudRate      = BaudRateList[BmmData->COMBaudRate[Index]].Value;
    553     NewTerminalContext->DataBitsIndex = BmmData->COMDataRate[Index];
    554     ASSERT (BmmData->COMDataRate[Index] < (ARRAY_SIZE (DataBitsList)));
    555     NewTerminalContext->DataBits      = (UINT8) DataBitsList[BmmData->COMDataRate[Index]].Value;
    556     NewTerminalContext->StopBitsIndex = BmmData->COMStopBits[Index];
    557     ASSERT (BmmData->COMStopBits[Index] < (ARRAY_SIZE (StopBitsList)));
    558     NewTerminalContext->StopBits      = (UINT8) StopBitsList[BmmData->COMStopBits[Index]].Value;
    559     NewTerminalContext->ParityIndex   = BmmData->COMParity[Index];
    560     ASSERT (BmmData->COMParity[Index] < (ARRAY_SIZE (ParityList)));
    561     NewTerminalContext->Parity        = (UINT8) ParityList[BmmData->COMParity[Index]].Value;
    562     NewTerminalContext->TerminalType  = BmmData->COMTerminalType[Index];
    563     NewTerminalContext->FlowControl   = BmmData->COMFlowControl[Index];
    564     ChangeTerminalDevicePath (
    565       NewTerminalContext->DevicePath,
    566       FALSE
    567       );
    568   }
    569 }
    570 
    571 /**
    572   Update the console content in ConsoleMenu.
    573 
    574   @param ConsoleName       The name for the console device type.
    575   @param BmmData           The BMM fake NV data.
    576 
    577 **/
    578 VOID
    579 UpdateConsoleContent(
    580   IN CHAR16                 *ConsoleName,
    581   IN BMM_FAKE_NV_DATA       *BmmData
    582   )
    583 {
    584   UINT16                          Index;
    585   BM_CONSOLE_CONTEXT              *NewConsoleContext;
    586   BM_TERMINAL_CONTEXT             *NewTerminalContext;
    587   BM_MENU_ENTRY                   *NewMenuEntry;
    588 
    589   if (StrCmp (ConsoleName, L"ConIn") == 0) {
    590     for (Index = 0; Index < ConsoleInpMenu.MenuNumber; Index++){
    591       NewMenuEntry                = BOpt_GetMenuEntry(&ConsoleInpMenu, Index);
    592       NewConsoleContext           = (BM_CONSOLE_CONTEXT *)NewMenuEntry->VariableContext;
    593       ASSERT (Index < MAX_MENU_NUMBER);
    594       NewConsoleContext->IsActive = BmmData->ConsoleInCheck[Index];
    595     }
    596     for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
    597       NewMenuEntry                = BOpt_GetMenuEntry (&TerminalMenu, Index);
    598       NewTerminalContext          = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
    599       ASSERT (Index + ConsoleInpMenu.MenuNumber < MAX_MENU_NUMBER);
    600       NewTerminalContext->IsConIn = BmmData->ConsoleInCheck[Index + ConsoleInpMenu.MenuNumber];
    601     }
    602   }
    603 
    604   if (StrCmp (ConsoleName, L"ConOut") == 0) {
    605     for (Index = 0; Index < ConsoleOutMenu.MenuNumber; Index++){
    606       NewMenuEntry                = BOpt_GetMenuEntry(&ConsoleOutMenu, Index);
    607       NewConsoleContext           = (BM_CONSOLE_CONTEXT *)NewMenuEntry->VariableContext;
    608       ASSERT (Index < MAX_MENU_NUMBER);
    609       NewConsoleContext->IsActive = BmmData->ConsoleOutCheck[Index];
    610     }
    611     for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
    612       NewMenuEntry                = BOpt_GetMenuEntry (&TerminalMenu, Index);
    613       NewTerminalContext          = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
    614       ASSERT (Index + ConsoleOutMenu.MenuNumber < MAX_MENU_NUMBER);
    615       NewTerminalContext->IsConOut = BmmData->ConsoleOutCheck[Index + ConsoleOutMenu.MenuNumber];
    616     }
    617   }
    618   if (StrCmp (ConsoleName, L"ErrOut") == 0) {
    619     for (Index = 0; Index < ConsoleErrMenu.MenuNumber; Index++){
    620       NewMenuEntry                = BOpt_GetMenuEntry(&ConsoleErrMenu, Index);
    621       NewConsoleContext           = (BM_CONSOLE_CONTEXT *)NewMenuEntry->VariableContext;
    622       ASSERT (Index < MAX_MENU_NUMBER);
    623       NewConsoleContext->IsActive = BmmData->ConsoleErrCheck[Index];
    624     }
    625     for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
    626       NewMenuEntry                = BOpt_GetMenuEntry (&TerminalMenu, Index);
    627       NewTerminalContext          = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
    628       ASSERT (Index + ConsoleErrMenu.MenuNumber < MAX_MENU_NUMBER);
    629       NewTerminalContext->IsStdErr = BmmData->ConsoleErrCheck[Index + ConsoleErrMenu.MenuNumber];
    630     }
    631   }
    632 }
    633 
    634 /**
    635   This function allows a caller to extract the current configuration for one
    636   or more named elements from the target driver.
    637 
    638   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    639   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
    640   @param Progress        On return, points to a character in the Request string.
    641                          Points to the string's null terminator if request was successful.
    642                          Points to the most recent '&' before the first failing name/value
    643                          pair (or the beginning of the string if the failure is in the
    644                          first name/value pair) if the request was not successful.
    645   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
    646                          has all values filled in for the names in the Request string.
    647                          String to be allocated by the called function.
    648 
    649   @retval  EFI_SUCCESS            The Results is filled with the requested values.
    650   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
    651   @retval  EFI_INVALID_PARAMETER  Request is NULL, illegal syntax, or unknown name.
    652   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
    653 
    654 **/
    655 EFI_STATUS
    656 EFIAPI
    657 BootMaintExtractConfig (
    658   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    659   IN  CONST EFI_STRING                       Request,
    660   OUT EFI_STRING                             *Progress,
    661   OUT EFI_STRING                             *Results
    662   )
    663 {
    664   EFI_STATUS         Status;
    665   UINTN              BufferSize;
    666   BMM_CALLBACK_DATA  *Private;
    667   EFI_STRING                       ConfigRequestHdr;
    668   EFI_STRING                       ConfigRequest;
    669   BOOLEAN                          AllocatedRequest;
    670   UINTN                            Size;
    671 
    672   if (Progress == NULL || Results == NULL) {
    673     return EFI_INVALID_PARAMETER;
    674   }
    675 
    676   *Progress = Request;
    677   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mBootMaintGuid, mBootMaintStorageName)) {
    678     return EFI_NOT_FOUND;
    679   }
    680 
    681   ConfigRequestHdr = NULL;
    682   ConfigRequest    = NULL;
    683   AllocatedRequest = FALSE;
    684   Size             = 0;
    685 
    686   Private = BMM_CALLBACK_DATA_FROM_THIS (This);
    687   //
    688   // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
    689   //
    690   BufferSize = sizeof (BMM_FAKE_NV_DATA);
    691   ConfigRequest = Request;
    692   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
    693     //
    694     // Request has no request element, construct full request string.
    695     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
    696     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
    697     //
    698     ConfigRequestHdr = HiiConstructConfigHdr (&mBootMaintGuid, mBootMaintStorageName, Private->BmmDriverHandle);
    699     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
    700     ConfigRequest = AllocateZeroPool (Size);
    701     ASSERT (ConfigRequest != NULL);
    702     AllocatedRequest = TRUE;
    703     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
    704     FreePool (ConfigRequestHdr);
    705   }
    706 
    707   Status = gHiiConfigRouting->BlockToConfig (
    708                                 gHiiConfigRouting,
    709                                 ConfigRequest,
    710                                 (UINT8 *) &Private->BmmFakeNvData,
    711                                 BufferSize,
    712                                 Results,
    713                                 Progress
    714                                 );
    715   //
    716   // Free the allocated config request string.
    717   //
    718   if (AllocatedRequest) {
    719     FreePool (ConfigRequest);
    720     ConfigRequest = NULL;
    721   }
    722   //
    723   // Set Progress string to the original request string.
    724   //
    725   if (Request == NULL) {
    726     *Progress = NULL;
    727   } else if (StrStr (Request, L"OFFSET") == NULL) {
    728     *Progress = Request + StrLen (Request);
    729   }
    730 
    731   return Status;
    732 }
    733 
    734 /**
    735   This function applies changes in a driver's configuration.
    736   Input is a Configuration, which has the routing data for this
    737   driver followed by name / value configuration pairs. The driver
    738   must apply those pairs to its configurable storage. If the
    739   driver's configuration is stored in a linear block of data
    740   and the driver's name / value pairs are in <BlockConfig>
    741   format, it may use the ConfigToBlock helper function (above) to
    742   simplify the job. Currently not implemented.
    743 
    744   @param[in]  This                Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    745   @param[in]  Configuration       A null-terminated Unicode string in
    746                                   <ConfigString> format.
    747   @param[out] Progress            A pointer to a string filled in with the
    748                                   offset of the most recent '&' before the
    749                                   first failing name / value pair (or the
    750                                   beginn ing of the string if the failure
    751                                   is in the first name / value pair) or
    752                                   the terminating NULL if all was
    753                                   successful.
    754 
    755   @retval EFI_SUCCESS             The results have been distributed or are
    756                                   awaiting distribution.
    757   @retval EFI_OUT_OF_RESOURCES    Not enough memory to store the
    758                                   parts of the results that must be
    759                                   stored awaiting possible future
    760                                   protocols.
    761   @retval EFI_INVALID_PARAMETERS  Passing in a NULL for the
    762                                   Results parameter would result
    763                                   in this type of error.
    764   @retval EFI_NOT_FOUND           Target for the specified routing data
    765                                   was not found.
    766 **/
    767 EFI_STATUS
    768 EFIAPI
    769 BootMaintRouteConfig (
    770   IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
    771   IN CONST EFI_STRING                     Configuration,
    772   OUT EFI_STRING                          *Progress
    773   )
    774 {
    775   EFI_STATUS                      Status;
    776   UINTN                           BufferSize;
    777   EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
    778   BMM_FAKE_NV_DATA                *NewBmmData;
    779   BMM_FAKE_NV_DATA                *OldBmmData;
    780   BM_MENU_ENTRY                   *NewMenuEntry;
    781   BM_LOAD_CONTEXT                 *NewLoadContext;
    782   UINT16                          Index;
    783   BOOLEAN                         TerminalAttChange;
    784   BMM_CALLBACK_DATA               *Private;
    785   UINTN                           Offset;
    786 
    787   if (Progress == NULL) {
    788     return EFI_INVALID_PARAMETER;
    789   }
    790   *Progress = Configuration;
    791 
    792   if (Configuration == NULL) {
    793     return EFI_INVALID_PARAMETER;
    794   }
    795 
    796   //
    797   // Check routing data in <ConfigHdr>.
    798   // Note: there is no name for Name/Value storage, only GUID will be checked
    799   //
    800   if (!HiiIsConfigHdrMatch (Configuration, &mBootMaintGuid, mBootMaintStorageName)) {
    801     return EFI_NOT_FOUND;
    802   }
    803 
    804   Status = gBS->LocateProtocol (
    805                   &gEfiHiiConfigRoutingProtocolGuid,
    806                   NULL,
    807                   (VOID **)&ConfigRouting
    808                   );
    809   if (EFI_ERROR (Status)) {
    810     return Status;
    811   }
    812 
    813   Private = BMM_CALLBACK_DATA_FROM_THIS (This);
    814   //
    815   // Get Buffer Storage data from EFI variable
    816   //
    817   BufferSize = sizeof (BMM_FAKE_NV_DATA);
    818   OldBmmData = &Private->BmmOldFakeNVData;
    819   NewBmmData = &Private->BmmFakeNvData;
    820   Offset     = 0;
    821   //
    822   // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
    823   //
    824   Status = ConfigRouting->ConfigToBlock (
    825                             ConfigRouting,
    826                             Configuration,
    827                             (UINT8 *) NewBmmData,
    828                             &BufferSize,
    829                             Progress
    830                             );
    831   ASSERT_EFI_ERROR (Status);
    832   //
    833   // Compare new and old BMM configuration data and only do action for modified item to
    834   // avoid setting unnecessary non-volatile variable
    835   //
    836 
    837   //
    838   // Check data which located in BMM main page and save the settings if need
    839   //
    840   if (CompareMem (&NewBmmData->BootNext, &OldBmmData->BootNext, sizeof (NewBmmData->BootNext)) != 0) {
    841     Status = Var_UpdateBootNext (Private);
    842     if (EFI_ERROR (Status)) {
    843       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootNext);
    844       goto Exit;
    845     }
    846   }
    847 
    848   //
    849   // Check data which located in Boot Options Menu and save the settings if need
    850   //
    851   if (CompareMem (NewBmmData->BootOptionDel, OldBmmData->BootOptionDel, sizeof (NewBmmData->BootOptionDel)) != 0) {
    852     for (Index = 0;
    853          ((Index < BootOptionMenu.MenuNumber) && (Index < (sizeof (NewBmmData->BootOptionDel) / sizeof (NewBmmData->BootOptionDel[0]))));
    854          Index ++) {
    855       NewMenuEntry            = BOpt_GetMenuEntry (&BootOptionMenu, Index);
    856       NewLoadContext          = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    857       NewLoadContext->Deleted = NewBmmData->BootOptionDel[Index];
    858       NewBmmData->BootOptionDel[Index] = FALSE;
    859       NewBmmData->BootOptionDelMark[Index] = FALSE;
    860     }
    861 
    862     Status = Var_DelBootOption ();
    863     if (EFI_ERROR (Status)) {
    864       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionDel);
    865       goto Exit;
    866     }
    867   }
    868 
    869   if (CompareMem (NewBmmData->BootOptionOrder, OldBmmData->BootOptionOrder, sizeof (NewBmmData->BootOptionOrder)) != 0) {
    870     Status = Var_UpdateBootOrder (Private);
    871     if (EFI_ERROR (Status)) {
    872       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionOrder);
    873       goto Exit;
    874     }
    875   }
    876 
    877   if (CompareMem (&NewBmmData->BootTimeOut, &OldBmmData->BootTimeOut, sizeof (NewBmmData->BootTimeOut)) != 0){
    878     Status = gRT->SetVariable(
    879                     L"Timeout",
    880                     &gEfiGlobalVariableGuid,
    881                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    882                     sizeof(UINT16),
    883                     &(NewBmmData->BootTimeOut)
    884                     );
    885     if (EFI_ERROR (Status)) {
    886       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootTimeOut);
    887       goto Exit;
    888     }
    889     Private->BmmOldFakeNVData.BootTimeOut = NewBmmData->BootTimeOut;
    890   }
    891 
    892   //
    893   // Check data which located in Driver Options Menu and save the settings if need
    894   //
    895   if (CompareMem (NewBmmData->DriverOptionDel, OldBmmData->DriverOptionDel, sizeof (NewBmmData->DriverOptionDel)) != 0) {
    896     for (Index = 0;
    897          ((Index < DriverOptionMenu.MenuNumber) && (Index < (sizeof (NewBmmData->DriverOptionDel) / sizeof (NewBmmData->DriverOptionDel[0]))));
    898          Index++) {
    899       NewMenuEntry            = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
    900       NewLoadContext          = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
    901       NewLoadContext->Deleted = NewBmmData->DriverOptionDel[Index];
    902       NewBmmData->DriverOptionDel[Index] = FALSE;
    903       NewBmmData->DriverOptionDelMark[Index] = FALSE;
    904     }
    905     Status = Var_DelDriverOption ();
    906     if (EFI_ERROR (Status)) {
    907       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionDel);
    908       goto Exit;
    909     }
    910   }
    911 
    912   if (CompareMem (NewBmmData->DriverOptionOrder, OldBmmData->DriverOptionOrder, sizeof (NewBmmData->DriverOptionOrder)) != 0) {
    913     Status = Var_UpdateDriverOrder (Private);
    914     if (EFI_ERROR (Status)) {
    915       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionOrder);
    916       goto Exit;
    917     }
    918   }
    919 
    920   if (CompareMem (&NewBmmData->ConsoleOutMode, &OldBmmData->ConsoleOutMode, sizeof (NewBmmData->ConsoleOutMode)) != 0){
    921     Status = Var_UpdateConMode(Private);
    922     if (EFI_ERROR (Status)) {
    923       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleOutMode);
    924       goto Exit;
    925     }
    926   }
    927 
    928   TerminalAttChange = FALSE;
    929   for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
    930 
    931     //
    932     // only need update modified items
    933     //
    934     if (CompareMem (&NewBmmData->COMBaudRate[Index], &OldBmmData->COMBaudRate[Index], sizeof (NewBmmData->COMBaudRate[Index])) == 0 &&
    935          CompareMem (&NewBmmData->COMDataRate[Index], &OldBmmData->COMDataRate[Index], sizeof (NewBmmData->COMDataRate[Index])) == 0 &&
    936          CompareMem (&NewBmmData->COMStopBits[Index], &OldBmmData->COMStopBits[Index], sizeof (NewBmmData->COMStopBits[Index])) == 0 &&
    937          CompareMem (&NewBmmData->COMParity[Index], &OldBmmData->COMParity[Index], sizeof (NewBmmData->COMParity[Index])) == 0 &&
    938          CompareMem (&NewBmmData->COMTerminalType[Index], &OldBmmData->COMTerminalType[Index], sizeof (NewBmmData->COMTerminalType[Index])) == 0 &&
    939          CompareMem (&NewBmmData->COMFlowControl[Index], &OldBmmData->COMFlowControl[Index], sizeof (NewBmmData->COMFlowControl[Index])) == 0) {
    940       continue;
    941     }
    942 
    943     TerminalAttChange = TRUE;
    944   }
    945   if (TerminalAttChange) {
    946     if (CompareMem (&NewBmmData->COMBaudRate[Index], &OldBmmData->COMBaudRate[Index], sizeof (NewBmmData->COMBaudRate[Index])) != 0) {
    947       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMBaudRate);
    948     } else if (CompareMem (&NewBmmData->COMDataRate[Index], &OldBmmData->COMDataRate[Index], sizeof (NewBmmData->COMDataRate[Index])) != 0) {
    949       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMDataRate);
    950     } else if (CompareMem (&NewBmmData->COMStopBits[Index], &OldBmmData->COMStopBits[Index], sizeof (NewBmmData->COMStopBits[Index])) != 0) {
    951       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMStopBits);
    952     } else if (CompareMem (&NewBmmData->COMParity[Index], &OldBmmData->COMParity[Index], sizeof (NewBmmData->COMParity[Index])) != 0) {
    953       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMParity);
    954     } else if (CompareMem (&NewBmmData->COMTerminalType[Index], &OldBmmData->COMTerminalType[Index], sizeof (NewBmmData->COMTerminalType[Index])) != 0) {
    955       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMTerminalType);
    956     } else if (CompareMem (&NewBmmData->COMFlowControl[Index], &OldBmmData->COMFlowControl[Index], sizeof (NewBmmData->COMFlowControl[Index])) != 0) {
    957       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, COMFlowControl);
    958     }
    959     Status = Var_UpdateConsoleInpOption ();
    960     if (EFI_ERROR (Status)) {
    961       goto Exit;
    962     }
    963     Status = Var_UpdateConsoleOutOption ();
    964     if (EFI_ERROR (Status)) {
    965       goto Exit;
    966     }
    967     Status = Var_UpdateErrorOutOption ();
    968     if (EFI_ERROR (Status)) {
    969       goto Exit;
    970     }
    971   }
    972   //
    973   // Check data which located in Console Options Menu and save the settings if need
    974   //
    975   if (CompareMem (NewBmmData->ConsoleInCheck, OldBmmData->ConsoleInCheck, sizeof (NewBmmData->ConsoleInCheck)) != 0){
    976     Status = Var_UpdateConsoleInpOption();
    977     if (EFI_ERROR (Status)) {
    978       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleInCheck);
    979       goto Exit;
    980     }
    981   }
    982 
    983   if (CompareMem (NewBmmData->ConsoleOutCheck, OldBmmData->ConsoleOutCheck, sizeof (NewBmmData->ConsoleOutCheck)) != 0){
    984     Status = Var_UpdateConsoleOutOption();
    985     if (EFI_ERROR (Status)) {
    986       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleOutCheck);
    987       goto Exit;
    988     }
    989   }
    990 
    991   if (CompareMem (NewBmmData->ConsoleErrCheck, OldBmmData->ConsoleErrCheck, sizeof (NewBmmData->ConsoleErrCheck)) != 0){
    992     Status = Var_UpdateErrorOutOption();
    993     if (EFI_ERROR (Status)) {
    994       Offset = OFFSET_OF (BMM_FAKE_NV_DATA, ConsoleErrCheck);
    995       goto Exit;
    996     }
    997   }
    998 
    999   if (CompareMem (NewBmmData->BootDescriptionData, OldBmmData->BootDescriptionData, sizeof (NewBmmData->BootDescriptionData)) != 0 ||
   1000        CompareMem (NewBmmData->BootOptionalData, OldBmmData->BootOptionalData, sizeof (NewBmmData->BootOptionalData)) != 0) {
   1001     Status = Var_UpdateBootOption (Private);
   1002     NewBmmData->BootOptionChanged = FALSE;
   1003     if (EFI_ERROR (Status)) {
   1004       if (CompareMem (NewBmmData->BootDescriptionData, OldBmmData->BootDescriptionData, sizeof (NewBmmData->BootDescriptionData)) != 0) {
   1005         Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootDescriptionData);
   1006       } else {
   1007         Offset = OFFSET_OF (BMM_FAKE_NV_DATA, BootOptionalData);
   1008       }
   1009       goto Exit;
   1010     }
   1011     BOpt_GetBootOptions (Private);
   1012   }
   1013 
   1014   if (CompareMem (NewBmmData->DriverDescriptionData, OldBmmData->DriverDescriptionData, sizeof (NewBmmData->DriverDescriptionData)) != 0 ||
   1015        CompareMem (NewBmmData->DriverOptionalData, OldBmmData->DriverOptionalData, sizeof (NewBmmData->DriverOptionalData)) != 0) {
   1016     Status = Var_UpdateDriverOption (
   1017               Private,
   1018               Private->BmmHiiHandle,
   1019               NewBmmData->DriverDescriptionData,
   1020               NewBmmData->DriverOptionalData,
   1021               NewBmmData->ForceReconnect
   1022               );
   1023     NewBmmData->DriverOptionChanged = FALSE;
   1024     NewBmmData->ForceReconnect      = TRUE;
   1025     if (EFI_ERROR (Status)) {
   1026       if (CompareMem (NewBmmData->DriverDescriptionData, OldBmmData->DriverDescriptionData, sizeof (NewBmmData->DriverDescriptionData)) != 0) {
   1027         Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverDescriptionData);
   1028       } else {
   1029         Offset = OFFSET_OF (BMM_FAKE_NV_DATA, DriverOptionalData);
   1030       }
   1031       goto Exit;
   1032     }
   1033 
   1034     BOpt_GetDriverOptions (Private);
   1035   }
   1036 
   1037   //
   1038   // After user do the save action, need to update OldBmmData.
   1039   //
   1040   CopyMem (OldBmmData, NewBmmData, sizeof (BMM_FAKE_NV_DATA));
   1041 
   1042   return EFI_SUCCESS;
   1043 
   1044 Exit:
   1045   //
   1046   // Fail to save the data, update the progress string.
   1047   //
   1048   *Progress = UpdateProgress (Offset, Configuration);
   1049   if (Status == EFI_OUT_OF_RESOURCES) {
   1050     return Status;
   1051   } else {
   1052     return EFI_NOT_FOUND;
   1053   }
   1054 }
   1055 
   1056 /**
   1057   This function processes the results of changes in configuration.
   1058 
   1059 
   1060   @param This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
   1061   @param Action             Specifies the type of action taken by the browser.
   1062   @param QuestionId         A unique value which is sent to the original exporting driver
   1063                             so that it can identify the type of data to expect.
   1064   @param Type               The type of value for the question.
   1065   @param Value              A pointer to the data being sent to the original exporting driver.
   1066   @param ActionRequest      On return, points to the action requested by the callback function.
   1067 
   1068   @retval EFI_SUCCESS           The callback successfully handled the action.
   1069   @retval EFI_OUT_OF_RESOURCES  Not enough storage is available to hold the variable and its data.
   1070   @retval EFI_DEVICE_ERROR      The variable could not be saved.
   1071   @retval EFI_UNSUPPORTED       The specified Action is not supported by the callback.
   1072   @retval EFI_INVALID_PARAMETER The parameter of Value or ActionRequest is invalid.
   1073 **/
   1074 EFI_STATUS
   1075 EFIAPI
   1076 BootMaintCallback (
   1077   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL         *This,
   1078   IN        EFI_BROWSER_ACTION                     Action,
   1079   IN        EFI_QUESTION_ID                        QuestionId,
   1080   IN        UINT8                                  Type,
   1081   IN        EFI_IFR_TYPE_VALUE                     *Value,
   1082   OUT       EFI_BROWSER_ACTION_REQUEST             *ActionRequest
   1083   )
   1084 {
   1085   BMM_CALLBACK_DATA *Private;
   1086   BM_MENU_ENTRY     *NewMenuEntry;
   1087   BMM_FAKE_NV_DATA  *CurrentFakeNVMap;
   1088   BMM_FAKE_NV_DATA  *OldFakeNVMap;
   1089   UINTN             Index;
   1090   EFI_DEVICE_PATH_PROTOCOL * File;
   1091 
   1092   if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED && Action != EFI_BROWSER_ACTION_FORM_OPEN) {
   1093     //
   1094     // Do nothing for other UEFI Action. Only do call back when data is changed or the form is open.
   1095     //
   1096     return EFI_UNSUPPORTED;
   1097   }
   1098 
   1099   Private        = BMM_CALLBACK_DATA_FROM_THIS (This);
   1100 
   1101   if (Action == EFI_BROWSER_ACTION_FORM_OPEN) {
   1102     if (QuestionId == KEY_VALUE_TRIGGER_FORM_OPEN_ACTION) {
   1103       if (!mFirstEnterBMMForm) {
   1104         //
   1105         // BMMUiLib depends on LegacyUi library to show legacy menus.
   1106         // If we want to show Legacy menus correctly in BMM page,
   1107         // we must do it after the LegacyUi library has already been initialized.
   1108         // Opening the BMM form is the appropriate time that the LegacyUi library has already been initialized.
   1109         // So we do the tasks which are related to legacy menus here.
   1110         // 1. Update the menus (including legacy munu) show in BootMiantenanceManager page.
   1111         // 2. Re-scan the BootOption menus (including the legacy boot option).
   1112         //
   1113         CustomizeMenus ();
   1114         BOpt_GetBootOptions (Private);
   1115         mFirstEnterBMMForm = TRUE;
   1116       }
   1117     }
   1118   }
   1119   //
   1120   // Retrieve uncommitted data from Form Browser
   1121   //
   1122   CurrentFakeNVMap = &Private->BmmFakeNvData;
   1123   OldFakeNVMap     = &Private->BmmOldFakeNVData;
   1124   HiiGetBrowserData (&mBootMaintGuid, mBootMaintStorageName, sizeof (BMM_FAKE_NV_DATA), (UINT8 *) CurrentFakeNVMap);
   1125 
   1126   if (Action == EFI_BROWSER_ACTION_CHANGING) {
   1127     if (Value == NULL) {
   1128       return EFI_INVALID_PARAMETER;
   1129     }
   1130 
   1131     UpdatePageId (Private, QuestionId);
   1132 
   1133     if (QuestionId < FILE_OPTION_OFFSET) {
   1134       if (QuestionId < CONFIG_OPTION_OFFSET) {
   1135         switch (QuestionId) {
   1136         case FORM_BOOT_ADD_ID:
   1137           // Leave BMM and enter FileExplorer.
   1138           ChooseFile (NULL, L".efi", CreateBootOptionFromFile, &File);
   1139           break;
   1140 
   1141         case FORM_DRV_ADD_FILE_ID:
   1142           // Leave BMM and enter FileExplorer.
   1143           ChooseFile (NULL, L".efi", CreateDriverOptionFromFile, &File);
   1144           break;
   1145 
   1146         case FORM_DRV_ADD_HANDLE_ID:
   1147           CleanUpPage (FORM_DRV_ADD_HANDLE_ID, Private);
   1148           UpdateDrvAddHandlePage (Private);
   1149           break;
   1150 
   1151         case FORM_BOOT_DEL_ID:
   1152           CleanUpPage (FORM_BOOT_DEL_ID, Private);
   1153           UpdateBootDelPage (Private);
   1154           break;
   1155 
   1156         case FORM_BOOT_CHG_ID:
   1157         case FORM_DRV_CHG_ID:
   1158           UpdatePageBody (QuestionId, Private);
   1159           break;
   1160 
   1161         case FORM_DRV_DEL_ID:
   1162           CleanUpPage (FORM_DRV_DEL_ID, Private);
   1163           UpdateDrvDelPage (Private);
   1164           break;
   1165 
   1166         case FORM_CON_IN_ID:
   1167         case FORM_CON_OUT_ID:
   1168         case FORM_CON_ERR_ID:
   1169           UpdatePageBody (QuestionId, Private);
   1170           break;
   1171 
   1172         case FORM_CON_MODE_ID:
   1173           CleanUpPage (FORM_CON_MODE_ID, Private);
   1174           UpdateConModePage (Private);
   1175           break;
   1176 
   1177         case FORM_CON_COM_ID:
   1178           CleanUpPage (FORM_CON_COM_ID, Private);
   1179           UpdateConCOMPage (Private);
   1180           break;
   1181 
   1182         default:
   1183           break;
   1184         }
   1185       } else if ((QuestionId >= TERMINAL_OPTION_OFFSET) && (QuestionId < CONSOLE_OPTION_OFFSET)) {
   1186         Index                  = (UINT16) (QuestionId - TERMINAL_OPTION_OFFSET);
   1187         Private->CurrentTerminal  = Index;
   1188 
   1189         CleanUpPage (FORM_CON_COM_SETUP_ID, Private);
   1190         UpdateTerminalPage (Private);
   1191 
   1192       } else if (QuestionId >= HANDLE_OPTION_OFFSET) {
   1193         Index                  = (UINT16) (QuestionId - HANDLE_OPTION_OFFSET);
   1194 
   1195         NewMenuEntry            = BOpt_GetMenuEntry (&DriverMenu, Index);
   1196         ASSERT (NewMenuEntry != NULL);
   1197         Private->HandleContext  = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
   1198 
   1199         CleanUpPage (FORM_DRV_ADD_HANDLE_DESC_ID, Private);
   1200 
   1201         Private->MenuEntry                  = NewMenuEntry;
   1202         Private->LoadContext->FilePathList  = Private->HandleContext->DevicePath;
   1203 
   1204         UpdateDriverAddHandleDescPage (Private);
   1205       }
   1206     }
   1207     if (QuestionId == KEY_VALUE_BOOT_FROM_FILE){
   1208       // Leave BMM and enter FileExplorer.
   1209       ChooseFile (NULL, L".efi", BootFromFile, &File);
   1210     }
   1211   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
   1212     if ((Value == NULL) || (ActionRequest == NULL)) {
   1213       return EFI_INVALID_PARAMETER;
   1214     }
   1215 
   1216     if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_BOOT) {
   1217       CurrentFakeNVMap->BootOptionChanged = FALSE;
   1218       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
   1219     } else if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_DRIVER) {
   1220       CurrentFakeNVMap->DriverOptionChanged = FALSE;
   1221       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
   1222     } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER) {
   1223       //
   1224       // Discard changes and exit formset
   1225       //
   1226       ZeroMem (CurrentFakeNVMap->DriverOptionalData, sizeof (CurrentFakeNVMap->DriverOptionalData));
   1227       ZeroMem (CurrentFakeNVMap->BootDescriptionData, sizeof (CurrentFakeNVMap->BootDescriptionData));
   1228       ZeroMem (OldFakeNVMap->DriverOptionalData, sizeof (OldFakeNVMap->DriverOptionalData));
   1229       ZeroMem (OldFakeNVMap->DriverDescriptionData, sizeof (OldFakeNVMap->DriverDescriptionData));
   1230       CurrentFakeNVMap->DriverOptionChanged = FALSE;
   1231       CurrentFakeNVMap->ForceReconnect      = TRUE;
   1232       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
   1233     } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_BOOT) {
   1234       //
   1235       // Discard changes and exit formset
   1236       //
   1237       ZeroMem (CurrentFakeNVMap->BootOptionalData, sizeof (CurrentFakeNVMap->BootOptionalData));
   1238       ZeroMem (CurrentFakeNVMap->BootDescriptionData, sizeof (CurrentFakeNVMap->BootDescriptionData));
   1239       ZeroMem (OldFakeNVMap->BootOptionalData, sizeof (OldFakeNVMap->BootOptionalData));
   1240       ZeroMem (OldFakeNVMap->BootDescriptionData, sizeof (OldFakeNVMap->BootDescriptionData));
   1241       CurrentFakeNVMap->BootOptionChanged = FALSE;
   1242       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
   1243     } else if (QuestionId == KEY_VALUE_BOOT_DESCRIPTION || QuestionId == KEY_VALUE_BOOT_OPTION) {
   1244       CurrentFakeNVMap->BootOptionChanged = TRUE;
   1245     } else if (QuestionId == KEY_VALUE_DRIVER_DESCRIPTION || QuestionId == KEY_VALUE_DRIVER_OPTION) {
   1246       CurrentFakeNVMap->DriverOptionChanged = TRUE;
   1247     }
   1248 
   1249     if ((QuestionId >= BOOT_OPTION_DEL_QUESTION_ID) && (QuestionId < BOOT_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) {
   1250       if (Value->b){
   1251         //
   1252         // Means user try to delete this boot option but not press F10 or "Commit Changes and Exit" menu.
   1253         //
   1254         CurrentFakeNVMap->BootOptionDelMark[QuestionId - BOOT_OPTION_DEL_QUESTION_ID] = TRUE;
   1255       } else {
   1256         //
   1257         // Means user remove the old check status.
   1258         //
   1259         CurrentFakeNVMap->BootOptionDelMark[QuestionId - BOOT_OPTION_DEL_QUESTION_ID] = FALSE;
   1260       }
   1261     } else if ((QuestionId >= DRIVER_OPTION_DEL_QUESTION_ID) && (QuestionId < DRIVER_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) {
   1262       if (Value->b){
   1263         CurrentFakeNVMap->DriverOptionDelMark[QuestionId - DRIVER_OPTION_DEL_QUESTION_ID] = TRUE;
   1264       } else {
   1265         CurrentFakeNVMap->DriverOptionDelMark[QuestionId - DRIVER_OPTION_DEL_QUESTION_ID] = FALSE;
   1266       }
   1267     } else {
   1268       switch (QuestionId) {
   1269       case KEY_VALUE_SAVE_AND_EXIT:
   1270       case KEY_VALUE_NO_SAVE_AND_EXIT:
   1271         if (QuestionId == KEY_VALUE_SAVE_AND_EXIT) {
   1272           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
   1273         } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT) {
   1274           DiscardChangeHandler (Private, CurrentFakeNVMap);
   1275           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
   1276         }
   1277 
   1278         break;
   1279 
   1280       case FORM_RESET:
   1281         gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
   1282         return EFI_UNSUPPORTED;
   1283 
   1284       default:
   1285         break;
   1286       }
   1287     }
   1288     //
   1289     // Update the content in Terminal menu and Console menu here.
   1290     //
   1291     if (QuestionId == COM_BAUD_RATE_QUESTION_ID + Private->CurrentTerminal || QuestionId == COM_DATA_RATE_QUESTION_ID + Private->CurrentTerminal ||
   1292       QuestionId == COM_PARITY_QUESTION_ID + Private->CurrentTerminal || QuestionId == COM_STOP_BITS_QUESTION_ID + Private->CurrentTerminal ||
   1293       QuestionId == COM_TERMINAL_QUESTION_ID + Private->CurrentTerminal || QuestionId == COM_FLOWCONTROL_QUESTION_ID + Private->CurrentTerminal
   1294     ) {
   1295       UpdateTerminalContent(CurrentFakeNVMap);
   1296     }
   1297     if ((QuestionId >= CON_IN_DEVICE_QUESTION_ID) && (QuestionId < CON_IN_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) {
   1298       UpdateConsoleContent (L"ConIn",CurrentFakeNVMap);
   1299     } else if ((QuestionId >= CON_OUT_DEVICE_QUESTION_ID) && (QuestionId < CON_OUT_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) {
   1300       UpdateConsoleContent (L"ConOut", CurrentFakeNVMap);
   1301     } else if ((QuestionId >= CON_ERR_DEVICE_QUESTION_ID) && (QuestionId < CON_ERR_DEVICE_QUESTION_ID + MAX_MENU_NUMBER)) {
   1302       UpdateConsoleContent (L"ConErr", CurrentFakeNVMap);
   1303     }
   1304   }
   1305 
   1306   //
   1307   // Pass changed uncommitted data back to Form Browser
   1308   //
   1309   HiiSetBrowserData (&mBootMaintGuid, mBootMaintStorageName, sizeof (BMM_FAKE_NV_DATA), (UINT8 *) CurrentFakeNVMap, NULL);
   1310 
   1311   return EFI_SUCCESS;
   1312 }
   1313 
   1314 /**
   1315   Discard all changes done to the BMM pages such as Boot Order change,
   1316   Driver order change.
   1317 
   1318   @param Private            The BMM context data.
   1319   @param CurrentFakeNVMap   The current Fack NV Map.
   1320 
   1321 **/
   1322 VOID
   1323 DiscardChangeHandler (
   1324   IN  BMM_CALLBACK_DATA               *Private,
   1325   IN  BMM_FAKE_NV_DATA                *CurrentFakeNVMap
   1326   )
   1327 {
   1328   UINT16  Index;
   1329 
   1330   switch (Private->BmmPreviousPageId) {
   1331   case FORM_BOOT_CHG_ID:
   1332     CopyMem (CurrentFakeNVMap->BootOptionOrder, Private->BmmOldFakeNVData.BootOptionOrder, sizeof (CurrentFakeNVMap->BootOptionOrder));
   1333     break;
   1334 
   1335   case FORM_DRV_CHG_ID:
   1336     CopyMem (CurrentFakeNVMap->DriverOptionOrder, Private->BmmOldFakeNVData.DriverOptionOrder, sizeof (CurrentFakeNVMap->DriverOptionOrder));
   1337     break;
   1338 
   1339   case FORM_BOOT_DEL_ID:
   1340     ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CurrentFakeNVMap->BootOptionDel) / sizeof (CurrentFakeNVMap->BootOptionDel[0])));
   1341     for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
   1342       CurrentFakeNVMap->BootOptionDel[Index] = FALSE;
   1343     }
   1344     break;
   1345 
   1346   case FORM_DRV_DEL_ID:
   1347     ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CurrentFakeNVMap->DriverOptionDel) / sizeof (CurrentFakeNVMap->DriverOptionDel[0])));
   1348     for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
   1349       CurrentFakeNVMap->DriverOptionDel[Index] = FALSE;
   1350     }
   1351     break;
   1352 
   1353   case FORM_BOOT_NEXT_ID:
   1354     CurrentFakeNVMap->BootNext = Private->BmmOldFakeNVData.BootNext;
   1355     break;
   1356 
   1357   case FORM_TIME_OUT_ID:
   1358     CurrentFakeNVMap->BootTimeOut = Private->BmmOldFakeNVData.BootTimeOut;
   1359     break;
   1360 
   1361   case FORM_DRV_ADD_HANDLE_DESC_ID:
   1362   case FORM_DRV_ADD_FILE_ID:
   1363   case FORM_DRV_ADD_HANDLE_ID:
   1364     CurrentFakeNVMap->DriverAddHandleDesc[0]          = 0x0000;
   1365     CurrentFakeNVMap->DriverAddHandleOptionalData[0]  = 0x0000;
   1366     break;
   1367 
   1368   default:
   1369     break;
   1370   }
   1371 }
   1372 
   1373 /**
   1374 
   1375   Update the menus in the BMM page.
   1376 
   1377 **/
   1378 VOID
   1379 CustomizeMenus (
   1380   VOID
   1381   )
   1382 {
   1383   VOID                        *StartOpCodeHandle;
   1384   VOID                        *EndOpCodeHandle;
   1385   EFI_IFR_GUID_LABEL          *StartGuidLabel;
   1386   EFI_IFR_GUID_LABEL          *EndGuidLabel;
   1387 
   1388   //
   1389   // Allocate space for creation of UpdateData Buffer
   1390   //
   1391   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
   1392   ASSERT (StartOpCodeHandle != NULL);
   1393 
   1394   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
   1395   ASSERT (EndOpCodeHandle != NULL);
   1396   //
   1397   // Create Hii Extend Label OpCode as the start opcode
   1398   //
   1399   StartGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
   1400   StartGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
   1401   StartGuidLabel->Number       = LABEL_FORM_MAIN_START;
   1402   //
   1403   // Create Hii Extend Label OpCode as the end opcode
   1404   //
   1405   EndGuidLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
   1406   EndGuidLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
   1407   EndGuidLabel->Number       = LABEL_FORM_MAIN_END;
   1408 
   1409   //
   1410   //Updata Front Page form
   1411   //
   1412   UiCustomizeBMMPage (
   1413     mBmmCallbackInfo->BmmHiiHandle,
   1414     StartOpCodeHandle
   1415     );
   1416 
   1417   HiiUpdateForm (
   1418     mBmmCallbackInfo->BmmHiiHandle,
   1419     &mBootMaintGuid,
   1420     FORM_MAIN_ID,
   1421     StartOpCodeHandle,
   1422     EndOpCodeHandle
   1423     );
   1424 
   1425   HiiFreeOpCodeHandle (StartOpCodeHandle);
   1426   HiiFreeOpCodeHandle (EndOpCodeHandle);
   1427 }
   1428 
   1429 /**
   1430    Create dynamic code for BMM and initialize all of BMM configuration data in BmmFakeNvData and
   1431    BmmOldFakeNVData member in BMM context data.
   1432 
   1433   @param CallbackData    The BMM context data.
   1434 
   1435 **/
   1436 VOID
   1437 InitializeBmmConfig (
   1438   IN  BMM_CALLBACK_DATA    *CallbackData
   1439   )
   1440 {
   1441   BM_MENU_ENTRY   *NewMenuEntry;
   1442   BM_LOAD_CONTEXT *NewLoadContext;
   1443   UINT16          Index;
   1444 
   1445   ASSERT (CallbackData != NULL);
   1446 
   1447   //
   1448   // Initialize data which located in BMM main page
   1449   //
   1450   CallbackData->BmmFakeNvData.BootNext = NONE_BOOTNEXT_VALUE;
   1451   for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
   1452     NewMenuEntry    = BOpt_GetMenuEntry (&BootOptionMenu, Index);
   1453     NewLoadContext  = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
   1454 
   1455     if (NewLoadContext->IsBootNext) {
   1456       CallbackData->BmmFakeNvData.BootNext = Index;
   1457       break;
   1458     }
   1459   }
   1460 
   1461   CallbackData->BmmFakeNvData.BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
   1462 
   1463   //
   1464   // Initialize data which located in Boot Options Menu
   1465   //
   1466   GetBootOrder (CallbackData);
   1467 
   1468   //
   1469   // Initialize data which located in Driver Options Menu
   1470   //
   1471   GetDriverOrder (CallbackData);
   1472 
   1473   //
   1474   // Initialize data which located in Console Options Menu
   1475   //
   1476   GetConsoleOutMode (CallbackData);
   1477   GetConsoleInCheck (CallbackData);
   1478   GetConsoleOutCheck (CallbackData);
   1479   GetConsoleErrCheck (CallbackData);
   1480   GetTerminalAttribute (CallbackData);
   1481 
   1482   CallbackData->BmmFakeNvData.ForceReconnect = TRUE;
   1483 
   1484   //
   1485   // Backup Initialize BMM configuartion data to BmmOldFakeNVData
   1486   //
   1487   CopyMem (&CallbackData->BmmOldFakeNVData, &CallbackData->BmmFakeNvData, sizeof (BMM_FAKE_NV_DATA));
   1488 }
   1489 
   1490 /**
   1491   Initialized all Menu Option List.
   1492 
   1493   @param CallbackData    The BMM context data.
   1494 
   1495 **/
   1496 VOID
   1497 InitAllMenu (
   1498   IN  BMM_CALLBACK_DATA    *CallbackData
   1499   )
   1500 {
   1501   InitializeListHead (&BootOptionMenu.Head);
   1502   InitializeListHead (&DriverOptionMenu.Head);
   1503   BOpt_GetBootOptions (CallbackData);
   1504   BOpt_GetDriverOptions (CallbackData);
   1505   BOpt_FindDrivers ();
   1506   InitializeListHead (&ConsoleInpMenu.Head);
   1507   InitializeListHead (&ConsoleOutMenu.Head);
   1508   InitializeListHead (&ConsoleErrMenu.Head);
   1509   InitializeListHead (&TerminalMenu.Head);
   1510   LocateSerialIo ();
   1511   GetAllConsoles ();
   1512   mAllMenuInit = TRUE;
   1513 }
   1514 
   1515 /**
   1516   Free up all Menu Option list.
   1517 
   1518 **/
   1519 VOID
   1520 FreeAllMenu (
   1521   VOID
   1522   )
   1523 {
   1524   if (!mAllMenuInit){
   1525     return;
   1526   }
   1527   BOpt_FreeMenu (&BootOptionMenu);
   1528   BOpt_FreeMenu (&DriverOptionMenu);
   1529   BOpt_FreeMenu (&DriverMenu);
   1530   FreeAllConsoles ();
   1531   mAllMenuInit = FALSE;
   1532 }
   1533 
   1534 /**
   1535   Initial the boot mode related parameters.
   1536 
   1537 **/
   1538 VOID
   1539 BmmInitialBootModeInfo (
   1540   VOID
   1541   )
   1542 {
   1543   EFI_STATUS                         Status;
   1544   EFI_GRAPHICS_OUTPUT_PROTOCOL       *GraphicsOutput;
   1545   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *SimpleTextOut;
   1546   UINTN                              BootTextColumn;
   1547   UINTN                              BootTextRow;
   1548 
   1549   if (mBmmModeInitialized) {
   1550     return;
   1551   }
   1552 
   1553   //
   1554   // After the console is ready, get current video resolution
   1555   // and text mode before launching setup at first time.
   1556   //
   1557   Status = gBS->HandleProtocol (
   1558                   gST->ConsoleOutHandle,
   1559                   &gEfiGraphicsOutputProtocolGuid,
   1560                   (VOID**)&GraphicsOutput
   1561                   );
   1562   if (EFI_ERROR (Status)) {
   1563     GraphicsOutput = NULL;
   1564   }
   1565 
   1566   Status = gBS->HandleProtocol (
   1567                   gST->ConsoleOutHandle,
   1568                   &gEfiSimpleTextOutProtocolGuid,
   1569                   (VOID**)&SimpleTextOut
   1570                   );
   1571   if (EFI_ERROR (Status)) {
   1572     SimpleTextOut = NULL;
   1573   }
   1574 
   1575   if (GraphicsOutput != NULL) {
   1576     //
   1577     // Get current video resolution and text mode.
   1578     //
   1579     mBmmBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
   1580     mBmmBootVerticalResolution   = GraphicsOutput->Mode->Info->VerticalResolution;
   1581   }
   1582 
   1583   if (SimpleTextOut != NULL) {
   1584     Status = SimpleTextOut->QueryMode (
   1585                               SimpleTextOut,
   1586                               SimpleTextOut->Mode->Mode,
   1587                               &BootTextColumn,
   1588                               &BootTextRow
   1589                               );
   1590     mBmmBootTextModeColumn = (UINT32)BootTextColumn;
   1591     mBmmBootTextModeRow    = (UINT32)BootTextRow;
   1592   }
   1593 
   1594   //
   1595   // Get user defined text mode for setup.
   1596   //
   1597   mBmmSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
   1598   mBmmSetupVerticalResolution   = PcdGet32 (PcdSetupVideoVerticalResolution);
   1599   mBmmSetupTextModeColumn       = PcdGet32 (PcdSetupConOutColumn);
   1600   mBmmSetupTextModeRow          = PcdGet32 (PcdSetupConOutRow);
   1601 
   1602   mBmmModeInitialized           = TRUE;
   1603 }
   1604 
   1605 /**
   1606 
   1607   Install Boot Maintenance Manager Menu driver.
   1608 
   1609   @param ImageHandle     The image handle.
   1610   @param SystemTable     The system table.
   1611 
   1612   @retval  EFI_SUCEESS  Install Boot manager menu success.
   1613   @retval  Other        Return error status.
   1614 
   1615 **/
   1616 EFI_STATUS
   1617 EFIAPI
   1618 BootMaintenanceManagerUiLibConstructor (
   1619   IN EFI_HANDLE                            ImageHandle,
   1620   IN EFI_SYSTEM_TABLE                      *SystemTable
   1621   )
   1622 
   1623 {
   1624   EFI_STATUS               Status;
   1625   UINT8                    *Ptr;
   1626 
   1627   Status = EFI_SUCCESS;
   1628 
   1629   //
   1630   // Install Device Path Protocol and Config Access protocol to driver handle
   1631   //
   1632   Status = gBS->InstallMultipleProtocolInterfaces (
   1633                   &mBmmCallbackInfo->BmmDriverHandle,
   1634                   &gEfiDevicePathProtocolGuid,
   1635                   &mBmmHiiVendorDevicePath,
   1636                   &gEfiHiiConfigAccessProtocolGuid,
   1637                   &mBmmCallbackInfo->BmmConfigAccess,
   1638                   NULL
   1639                   );
   1640   ASSERT_EFI_ERROR (Status);
   1641 
   1642   //
   1643   // Post our Boot Maint VFR binary to the HII database.
   1644   //
   1645   mBmmCallbackInfo->BmmHiiHandle = HiiAddPackages (
   1646                                     &mBootMaintGuid,
   1647                                     mBmmCallbackInfo->BmmDriverHandle,
   1648                                     BootMaintenanceManagerBin,
   1649                                     BootMaintenanceManagerUiLibStrings,
   1650                                     NULL
   1651                                     );
   1652   ASSERT (mBmmCallbackInfo->BmmHiiHandle != NULL);
   1653 
   1654   //
   1655   // Locate Formbrowser2 protocol
   1656   //
   1657   Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &mBmmCallbackInfo->FormBrowser2);
   1658   ASSERT_EFI_ERROR (Status);
   1659 
   1660   EfiBootManagerRefreshAllBootOption ();
   1661 
   1662   //
   1663   // Create LoadOption in BmmCallbackInfo for Driver Callback
   1664   //
   1665   Ptr = AllocateZeroPool (sizeof (BM_LOAD_CONTEXT) + sizeof (BM_FILE_CONTEXT) + sizeof (BM_HANDLE_CONTEXT) + sizeof (BM_MENU_ENTRY));
   1666   ASSERT (Ptr != NULL);
   1667 
   1668   //
   1669   // Initialize Bmm callback data.
   1670   //
   1671   mBmmCallbackInfo->LoadContext = (BM_LOAD_CONTEXT *) Ptr;
   1672   Ptr += sizeof (BM_LOAD_CONTEXT);
   1673 
   1674   mBmmCallbackInfo->FileContext = (BM_FILE_CONTEXT *) Ptr;
   1675   Ptr += sizeof (BM_FILE_CONTEXT);
   1676 
   1677   mBmmCallbackInfo->HandleContext = (BM_HANDLE_CONTEXT *) Ptr;
   1678   Ptr += sizeof (BM_HANDLE_CONTEXT);
   1679 
   1680   mBmmCallbackInfo->MenuEntry     = (BM_MENU_ENTRY *) Ptr;
   1681 
   1682   mBmmCallbackInfo->BmmPreviousPageId  = FORM_MAIN_ID;
   1683   mBmmCallbackInfo->BmmCurrentPageId   = FORM_MAIN_ID;
   1684 
   1685   InitAllMenu (mBmmCallbackInfo);
   1686 
   1687   CreateUpdateData();
   1688   //
   1689   // Update boot maintenance manager page
   1690   //
   1691   InitializeBmmConfig(mBmmCallbackInfo);
   1692 
   1693   BmmInitialBootModeInfo();
   1694 
   1695   return EFI_SUCCESS;
   1696 }
   1697 
   1698 /**
   1699   Unloads the application and its installed protocol.
   1700 
   1701   @param ImageHandle       Handle that identifies the image to be unloaded.
   1702   @param  SystemTable      The system table.
   1703 
   1704   @retval EFI_SUCCESS      The image has been unloaded.
   1705 
   1706 **/
   1707 EFI_STATUS
   1708 EFIAPI
   1709 BootMaintenanceManagerUiLibDestructor (
   1710   IN EFI_HANDLE                            ImageHandle,
   1711   IN EFI_SYSTEM_TABLE                      *SystemTable
   1712   )
   1713 
   1714 {
   1715   if (mStartOpCodeHandle != NULL) {
   1716     HiiFreeOpCodeHandle (mStartOpCodeHandle);
   1717   }
   1718 
   1719   if (mEndOpCodeHandle != NULL) {
   1720     HiiFreeOpCodeHandle (mEndOpCodeHandle);
   1721   }
   1722 
   1723   FreeAllMenu ();
   1724 
   1725   //
   1726   // Remove our IFR data from HII database
   1727   //
   1728   HiiRemovePackages (mBmmCallbackInfo->BmmHiiHandle);
   1729 
   1730   gBS->UninstallMultipleProtocolInterfaces (
   1731          mBmmCallbackInfo->BmmDriverHandle,
   1732          &gEfiDevicePathProtocolGuid,
   1733          &mBmmHiiVendorDevicePath,
   1734          &gEfiHiiConfigAccessProtocolGuid,
   1735          &mBmmCallbackInfo->BmmConfigAccess,
   1736          NULL
   1737          );
   1738 
   1739   FreePool (mBmmCallbackInfo->LoadContext);
   1740 
   1741   return EFI_SUCCESS;
   1742 }
   1743 
   1744