Home | History | Annotate | Download | only in BdsDxe
      1 /** @file
      2   FrontPage routines to handle the callbacks and browser calls
      3 
      4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "Bds.h"
     16 #include "FrontPage.h"
     17 #include "Language.h"
     18 #include "Hotkey.h"
     19 
     20 BOOLEAN   mModeInitialized = FALSE;
     21 
     22 BOOLEAN   gConnectAllHappened = FALSE;
     23 UINTN     gCallbackKey;
     24 CHAR8     *mLanguageString;
     25 
     26 //
     27 // Boot video resolution and text mode.
     28 //
     29 UINT32    mBootHorizontalResolution    = 0;
     30 UINT32    mBootVerticalResolution      = 0;
     31 UINT32    mBootTextModeColumn          = 0;
     32 UINT32    mBootTextModeRow             = 0;
     33 //
     34 // BIOS setup video resolution and text mode.
     35 //
     36 UINT32    mSetupTextModeColumn         = 0;
     37 UINT32    mSetupTextModeRow            = 0;
     38 UINT32    mSetupHorizontalResolution   = 0;
     39 UINT32    mSetupVerticalResolution     = 0;
     40 
     41 EFI_FORM_BROWSER2_PROTOCOL      *gFormBrowser2;
     42 
     43 FRONT_PAGE_CALLBACK_DATA  gFrontPagePrivate = {
     44   FRONT_PAGE_CALLBACK_DATA_SIGNATURE,
     45   NULL,
     46   NULL,
     47   NULL,
     48   {
     49     FakeExtractConfig,
     50     FakeRouteConfig,
     51     FrontPageCallback
     52   }
     53 };
     54 
     55 HII_VENDOR_DEVICE_PATH  mFrontPageHiiVendorDevicePath = {
     56   {
     57     {
     58       HARDWARE_DEVICE_PATH,
     59       HW_VENDOR_DP,
     60       {
     61         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
     62         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
     63       }
     64     },
     65     FRONT_PAGE_FORMSET_GUID
     66   },
     67   {
     68     END_DEVICE_PATH_TYPE,
     69     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     70     {
     71       (UINT8) (END_DEVICE_PATH_LENGTH),
     72       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
     73     }
     74   }
     75 };
     76 
     77 /**
     78   This function allows a caller to extract the current configuration for one
     79   or more named elements from the target driver.
     80 
     81 
     82   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
     83   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
     84   @param Progress        On return, points to a character in the Request string.
     85                          Points to the string's null terminator if request was successful.
     86                          Points to the most recent '&' before the first failing name/value
     87                          pair (or the beginning of the string if the failure is in the
     88                          first name/value pair) if the request was not successful.
     89   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
     90                          has all values filled in for the names in the Request string.
     91                          String to be allocated by the called function.
     92 
     93   @retval  EFI_SUCCESS            The Results is filled with the requested values.
     94   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
     95   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
     96   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
     97 
     98 **/
     99 EFI_STATUS
    100 EFIAPI
    101 FakeExtractConfig (
    102   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    103   IN  CONST EFI_STRING                       Request,
    104   OUT EFI_STRING                             *Progress,
    105   OUT EFI_STRING                             *Results
    106   )
    107 {
    108   if (Progress == NULL || Results == NULL) {
    109     return EFI_INVALID_PARAMETER;
    110   }
    111   *Progress = Request;
    112   return EFI_NOT_FOUND;
    113 }
    114 
    115 /**
    116   This function processes the results of changes in configuration.
    117 
    118 
    119   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    120   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.
    121   @param Progress        A pointer to a string filled in with the offset of the most
    122                          recent '&' before the first failing name/value pair (or the
    123                          beginning of the string if the failure is in the first
    124                          name/value pair) or the terminating NULL if all was successful.
    125 
    126   @retval  EFI_SUCCESS            The Results is processed successfully.
    127   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.
    128   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
    129 
    130 **/
    131 EFI_STATUS
    132 EFIAPI
    133 FakeRouteConfig (
    134   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    135   IN  CONST EFI_STRING                       Configuration,
    136   OUT EFI_STRING                             *Progress
    137   )
    138 {
    139   if (Configuration == NULL || Progress == NULL) {
    140     return EFI_INVALID_PARAMETER;
    141   }
    142 
    143   *Progress = Configuration;
    144   if (!HiiIsConfigHdrMatch (Configuration, &gBootMaintFormSetGuid, mBootMaintStorageName)
    145       && !HiiIsConfigHdrMatch (Configuration, &gFileExploreFormSetGuid, mFileExplorerStorageName)) {
    146     return EFI_NOT_FOUND;
    147   }
    148 
    149   *Progress = Configuration + StrLen (Configuration);
    150   return EFI_SUCCESS;
    151 }
    152 
    153 /**
    154   This function processes the results of changes in configuration.
    155 
    156 
    157   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    158   @param Action          Specifies the type of action taken by the browser.
    159   @param QuestionId      A unique value which is sent to the original exporting driver
    160                          so that it can identify the type of data to expect.
    161   @param Type            The type of value for the question.
    162   @param Value           A pointer to the data being sent to the original exporting driver.
    163   @param ActionRequest   On return, points to the action requested by the callback function.
    164 
    165   @retval  EFI_SUCCESS           The callback successfully handled the action.
    166   @retval  EFI_OUT_OF_RESOURCES  Not enough storage is available to hold the variable and its data.
    167   @retval  EFI_DEVICE_ERROR      The variable could not be saved.
    168   @retval  EFI_UNSUPPORTED       The specified Action is not supported by the callback.
    169 
    170 **/
    171 EFI_STATUS
    172 EFIAPI
    173 FrontPageCallback (
    174   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    175   IN  EFI_BROWSER_ACTION                     Action,
    176   IN  EFI_QUESTION_ID                        QuestionId,
    177   IN  UINT8                                  Type,
    178   IN  EFI_IFR_TYPE_VALUE                     *Value,
    179   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
    180   )
    181 {
    182   CHAR8                         *LangCode;
    183   CHAR8                         *Lang;
    184   UINTN                         Index;
    185 
    186   if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
    187     //
    188     // All other action return unsupported.
    189     //
    190     return EFI_UNSUPPORTED;
    191   }
    192 
    193   gCallbackKey = QuestionId;
    194 
    195   if (Action == EFI_BROWSER_ACTION_CHANGED) {
    196     if ((Value == NULL) || (ActionRequest == NULL)) {
    197       return EFI_INVALID_PARAMETER;
    198     }
    199 
    200     switch (QuestionId) {
    201     case FRONT_PAGE_KEY_CONTINUE:
    202       //
    203       // This is the continue - clear the screen and return an error to get out of FrontPage loop
    204       //
    205       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
    206       break;
    207 
    208     case FRONT_PAGE_KEY_LANGUAGE:
    209       //
    210       // Allocate working buffer for RFC 4646 language in supported LanguageString.
    211       //
    212       Lang = AllocatePool (AsciiStrSize (mLanguageString));
    213       ASSERT (Lang != NULL);
    214 
    215       Index = 0;
    216       LangCode = mLanguageString;
    217       while (*LangCode != 0) {
    218         GetNextLanguage (&LangCode, Lang);
    219 
    220         if (Index == Value->u8) {
    221           break;
    222         }
    223 
    224         Index++;
    225       }
    226 
    227       if (Index == Value->u8) {
    228         BdsDxeSetVariableAndReportStatusCodeOnError (
    229                         L"PlatformLang",
    230                         &gEfiGlobalVariableGuid,
    231                         EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
    232                         AsciiStrSize (Lang),
    233                         Lang
    234                         );
    235       } else {
    236         ASSERT (FALSE);
    237       }
    238 
    239       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
    240 
    241       FreePool (Lang);
    242       break;
    243 
    244     default:
    245       break;
    246     }
    247   } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
    248     if (Value == NULL) {
    249       return EFI_INVALID_PARAMETER;
    250     }
    251 
    252     //
    253     // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can
    254     // describe to their customers in documentation how to find their setup information (namely
    255     // under the device manager and specific buckets)
    256     //
    257     switch (QuestionId) {
    258     case FRONT_PAGE_KEY_BOOT_MANAGER:
    259       //
    260       // Boot Manager
    261       //
    262       break;
    263 
    264     case FRONT_PAGE_KEY_DEVICE_MANAGER:
    265       //
    266       // Device Manager
    267       //
    268       break;
    269 
    270     case FRONT_PAGE_KEY_BOOT_MAINTAIN:
    271       //
    272       // Boot Maintenance Manager
    273       //
    274       break;
    275 
    276     default:
    277       gCallbackKey = 0;
    278       break;
    279     }
    280   }
    281 
    282   return EFI_SUCCESS;
    283 }
    284 
    285 /**
    286   Initialize HII information for the FrontPage
    287 
    288 
    289   @param InitializeHiiData    TRUE if HII elements need to be initialized.
    290 
    291   @retval  EFI_SUCCESS        The operation is successful.
    292   @retval  EFI_DEVICE_ERROR   If the dynamic opcode creation failed.
    293 
    294 **/
    295 EFI_STATUS
    296 InitializeFrontPage (
    297   IN BOOLEAN                         InitializeHiiData
    298   )
    299 {
    300   EFI_STATUS                  Status;
    301   CHAR8                       *LangCode;
    302   CHAR8                       *Lang;
    303   CHAR8                       *CurrentLang;
    304   UINTN                       OptionCount;
    305   CHAR16                      *StringBuffer;
    306   EFI_HII_HANDLE              HiiHandle;
    307   VOID                        *OptionsOpCodeHandle;
    308   VOID                        *StartOpCodeHandle;
    309   VOID                        *EndOpCodeHandle;
    310   EFI_IFR_GUID_LABEL          *StartLabel;
    311   EFI_IFR_GUID_LABEL          *EndLabel;
    312   EFI_HII_STRING_PROTOCOL     *HiiString;
    313   UINTN                       StringSize;
    314 
    315   Lang         = NULL;
    316   StringBuffer = NULL;
    317 
    318   if (InitializeHiiData) {
    319     //
    320     // Initialize the Device Manager
    321     //
    322     InitializeDeviceManager ();
    323 
    324     //
    325     // Initialize the Device Manager
    326     //
    327     InitializeBootManager ();
    328 
    329     gCallbackKey  = 0;
    330 
    331     //
    332     // Locate Hii relative protocols
    333     //
    334     Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFormBrowser2);
    335     if (EFI_ERROR (Status)) {
    336       return Status;
    337     }
    338 
    339     //
    340     // Install Device Path Protocol and Config Access protocol to driver handle
    341     //
    342     Status = gBS->InstallMultipleProtocolInterfaces (
    343                     &gFrontPagePrivate.DriverHandle,
    344                     &gEfiDevicePathProtocolGuid,
    345                     &mFrontPageHiiVendorDevicePath,
    346                     &gEfiHiiConfigAccessProtocolGuid,
    347                     &gFrontPagePrivate.ConfigAccess,
    348                     NULL
    349                     );
    350     ASSERT_EFI_ERROR (Status);
    351 
    352     //
    353     // Publish our HII data
    354     //
    355     gFrontPagePrivate.HiiHandle = HiiAddPackages (
    356                                     &gFrontPageFormSetGuid,
    357                                     gFrontPagePrivate.DriverHandle,
    358                                     FrontPageVfrBin,
    359                                     BdsDxeStrings,
    360                                     NULL
    361                                     );
    362     if (gFrontPagePrivate.HiiHandle == NULL) {
    363       return EFI_OUT_OF_RESOURCES;
    364     }
    365   }
    366 
    367 
    368   //
    369   // Init OpCode Handle and Allocate space for creation of UpdateData Buffer
    370   //
    371   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
    372   ASSERT (StartOpCodeHandle != NULL);
    373 
    374   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
    375   ASSERT (EndOpCodeHandle != NULL);
    376 
    377   OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
    378   ASSERT (OptionsOpCodeHandle != NULL);
    379   //
    380   // Create Hii Extend Label OpCode as the start opcode
    381   //
    382   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    383   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    384   StartLabel->Number       = LABEL_SELECT_LANGUAGE;
    385 
    386   //
    387   // Create Hii Extend Label OpCode as the end opcode
    388   //
    389   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    390   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    391   EndLabel->Number       = LABEL_END;
    392 
    393   //
    394   // Collect the languages from what our current Language support is based on our VFR
    395   //
    396   HiiHandle = gFrontPagePrivate.HiiHandle;
    397 
    398   GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL);
    399 
    400   //
    401   // Get Support language list from variable.
    402   //
    403   if (mLanguageString == NULL){
    404     GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&mLanguageString, NULL);
    405     if (mLanguageString == NULL) {
    406       mLanguageString = AllocateCopyPool (
    407                                  AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),
    408                                  (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)
    409                                  );
    410       ASSERT (mLanguageString != NULL);
    411     }
    412   }
    413 
    414   if (gFrontPagePrivate.LanguageToken == NULL) {
    415     //
    416     // Count the language list number.
    417     //
    418     LangCode      = mLanguageString;
    419     Lang          = AllocatePool (AsciiStrSize (mLanguageString));
    420     ASSERT (Lang != NULL);
    421     OptionCount = 0;
    422     while (*LangCode != 0) {
    423       GetNextLanguage (&LangCode, Lang);
    424       OptionCount ++;
    425     }
    426 
    427     //
    428     // Allocate extra 1 as the end tag.
    429     //
    430     gFrontPagePrivate.LanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID));
    431     ASSERT (gFrontPagePrivate.LanguageToken != NULL);
    432 
    433     Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
    434     ASSERT_EFI_ERROR (Status);
    435 
    436     LangCode     = mLanguageString;
    437     OptionCount  = 0;
    438     while (*LangCode != 0) {
    439       GetNextLanguage (&LangCode, Lang);
    440 
    441       StringSize = 0;
    442       Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
    443       if (Status == EFI_BUFFER_TOO_SMALL) {
    444         StringBuffer = AllocateZeroPool (StringSize);
    445         ASSERT (StringBuffer != NULL);
    446         Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
    447         ASSERT_EFI_ERROR (Status);
    448       }
    449 
    450       if (EFI_ERROR (Status)) {
    451         StringBuffer = AllocatePool (AsciiStrSize (Lang) * sizeof (CHAR16));
    452         ASSERT (StringBuffer != NULL);
    453         AsciiStrToUnicodeStr (Lang, StringBuffer);
    454       }
    455 
    456       ASSERT (StringBuffer != NULL);
    457       gFrontPagePrivate.LanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);
    458       FreePool (StringBuffer);
    459 
    460       OptionCount++;
    461     }
    462   }
    463 
    464   ASSERT (gFrontPagePrivate.LanguageToken != NULL);
    465   LangCode     = mLanguageString;
    466   OptionCount  = 0;
    467   if (Lang == NULL) {
    468     Lang = AllocatePool (AsciiStrSize (mLanguageString));
    469     ASSERT (Lang != NULL);
    470   }
    471   while (*LangCode != 0) {
    472     GetNextLanguage (&LangCode, Lang);
    473 
    474     if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) {
    475       HiiCreateOneOfOptionOpCode (
    476         OptionsOpCodeHandle,
    477         gFrontPagePrivate.LanguageToken[OptionCount],
    478         EFI_IFR_OPTION_DEFAULT,
    479         EFI_IFR_NUMERIC_SIZE_1,
    480         (UINT8) OptionCount
    481         );
    482     } else {
    483       HiiCreateOneOfOptionOpCode (
    484         OptionsOpCodeHandle,
    485         gFrontPagePrivate.LanguageToken[OptionCount],
    486         0,
    487         EFI_IFR_NUMERIC_SIZE_1,
    488         (UINT8) OptionCount
    489         );
    490     }
    491 
    492     OptionCount++;
    493   }
    494 
    495   if (CurrentLang != NULL) {
    496     FreePool (CurrentLang);
    497   }
    498   FreePool (Lang);
    499 
    500   HiiCreateOneOfOpCode (
    501     StartOpCodeHandle,
    502     FRONT_PAGE_KEY_LANGUAGE,
    503     0,
    504     0,
    505     STRING_TOKEN (STR_LANGUAGE_SELECT),
    506     STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),
    507     EFI_IFR_FLAG_CALLBACK,
    508     EFI_IFR_NUMERIC_SIZE_1,
    509     OptionsOpCodeHandle,
    510     NULL
    511     );
    512 
    513   Status = HiiUpdateForm (
    514              HiiHandle,
    515              &gFrontPageFormSetGuid,
    516              FRONT_PAGE_FORM_ID,
    517              StartOpCodeHandle, // LABEL_SELECT_LANGUAGE
    518              EndOpCodeHandle    // LABEL_END
    519              );
    520 
    521   HiiFreeOpCodeHandle (StartOpCodeHandle);
    522   HiiFreeOpCodeHandle (EndOpCodeHandle);
    523   HiiFreeOpCodeHandle (OptionsOpCodeHandle);
    524   return Status;
    525 }
    526 
    527 /**
    528   Call the browser and display the front page
    529 
    530   @return   Status code that will be returned by
    531             EFI_FORM_BROWSER2_PROTOCOL.SendForm ().
    532 
    533 **/
    534 EFI_STATUS
    535 CallFrontPage (
    536   VOID
    537   )
    538 {
    539   EFI_STATUS                  Status;
    540   EFI_BROWSER_ACTION_REQUEST  ActionRequest;
    541 
    542   //
    543   // Begin waiting for USER INPUT
    544   //
    545   REPORT_STATUS_CODE (
    546     EFI_PROGRESS_CODE,
    547     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_INPUT_WAIT)
    548     );
    549 
    550   ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
    551   Status = gFormBrowser2->SendForm (
    552                             gFormBrowser2,
    553                             &gFrontPagePrivate.HiiHandle,
    554                             1,
    555                             &gFrontPageFormSetGuid,
    556                             0,
    557                             NULL,
    558                             &ActionRequest
    559                             );
    560   //
    561   // Check whether user change any option setting which needs a reset to be effective
    562   //
    563   if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
    564     EnableResetRequired ();
    565   }
    566 
    567   return Status;
    568 }
    569 
    570 /**
    571   Acquire the string associated with the ProducerGuid and return it.
    572 
    573 
    574   @param ProducerGuid    The Guid to search the HII database for
    575   @param Token           The token value of the string to extract
    576   @param String          The string that is extracted
    577 
    578   @retval  EFI_SUCCESS  The function returns EFI_SUCCESS always.
    579 
    580 **/
    581 EFI_STATUS
    582 GetProducerString (
    583   IN      EFI_GUID                  *ProducerGuid,
    584   IN      EFI_STRING_ID             Token,
    585   OUT     CHAR16                    **String
    586   )
    587 {
    588   EFI_STRING      TmpString;
    589 
    590   TmpString = HiiGetPackageString (ProducerGuid, Token, NULL);
    591   if (TmpString == NULL) {
    592     *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));
    593   } else {
    594     *String = TmpString;
    595   }
    596 
    597   return EFI_SUCCESS;
    598 }
    599 
    600 /**
    601   Convert Processor Frequency Data to a string.
    602 
    603   @param ProcessorFrequency The frequency data to process
    604   @param Base10Exponent     The exponent based on 10
    605   @param String             The string that is created
    606 
    607 **/
    608 VOID
    609 ConvertProcessorToString (
    610   IN  UINT16                               ProcessorFrequency,
    611   IN  UINT16                               Base10Exponent,
    612   OUT CHAR16                               **String
    613   )
    614 {
    615   CHAR16  *StringBuffer;
    616   UINTN   Index;
    617   UINT32  FreqMhz;
    618 
    619   if (Base10Exponent >= 6) {
    620     FreqMhz = ProcessorFrequency;
    621     for (Index = 0; Index < (UINTN) (Base10Exponent - 6); Index++) {
    622       FreqMhz *= 10;
    623     }
    624   } else {
    625     FreqMhz = 0;
    626   }
    627 
    628   StringBuffer = AllocateZeroPool (0x20);
    629   ASSERT (StringBuffer != NULL);
    630   Index = UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, FreqMhz / 1000, 3);
    631   StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L".");
    632   UnicodeValueToString (StringBuffer + Index + 1, PREFIX_ZERO, (FreqMhz % 1000) / 10, 2);
    633   StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L" GHz");
    634   *String = (CHAR16 *) StringBuffer;
    635   return ;
    636 }
    637 
    638 
    639 /**
    640   Convert Memory Size to a string.
    641 
    642   @param MemorySize      The size of the memory to process
    643   @param String          The string that is created
    644 
    645 **/
    646 VOID
    647 ConvertMemorySizeToString (
    648   IN  UINT32          MemorySize,
    649   OUT CHAR16          **String
    650   )
    651 {
    652   CHAR16  *StringBuffer;
    653 
    654   StringBuffer = AllocateZeroPool (0x20);
    655   ASSERT (StringBuffer != NULL);
    656   UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, MemorySize, 6);
    657   StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L" MB RAM");
    658 
    659   *String = (CHAR16 *) StringBuffer;
    660 
    661   return ;
    662 }
    663 
    664 /**
    665 
    666   Acquire the string associated with the Index from smbios structure and return it.
    667   The caller is responsible for free the string buffer.
    668 
    669   @param    OptionalStrStart  The start position to search the string
    670   @param    Index             The index of the string to extract
    671   @param    String            The string that is extracted
    672 
    673   @retval   EFI_SUCCESS       The function returns EFI_SUCCESS always.
    674 
    675 **/
    676 EFI_STATUS
    677 GetOptionalStringByIndex (
    678   IN      CHAR8                   *OptionalStrStart,
    679   IN      UINT8                   Index,
    680   OUT     CHAR16                  **String
    681   )
    682 {
    683   UINTN          StrSize;
    684 
    685   if (Index == 0) {
    686     *String = AllocateZeroPool (sizeof (CHAR16));
    687     return EFI_SUCCESS;
    688   }
    689 
    690   StrSize = 0;
    691   do {
    692     Index--;
    693     OptionalStrStart += StrSize;
    694     StrSize           = AsciiStrSize (OptionalStrStart);
    695   } while (OptionalStrStart[StrSize] != 0 && Index != 0);
    696 
    697   if ((Index != 0) || (StrSize == 1)) {
    698     //
    699     // Meet the end of strings set but Index is non-zero, or
    700     // Find an empty string
    701     //
    702     *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));
    703   } else {
    704     *String = AllocatePool (StrSize * sizeof (CHAR16));
    705     AsciiStrToUnicodeStr (OptionalStrStart, *String);
    706   }
    707 
    708   return EFI_SUCCESS;
    709 }
    710 
    711 
    712 /**
    713   Update the banner information for the Front Page based on DataHub information.
    714 
    715 **/
    716 VOID
    717 UpdateFrontPageStrings (
    718   VOID
    719   )
    720 {
    721   UINT8                             StrIndex;
    722   CHAR16                            *NewString;
    723   BOOLEAN                           Find[5];
    724   EFI_STATUS                        Status;
    725   EFI_STRING_ID                     TokenToUpdate;
    726   EFI_SMBIOS_HANDLE                 SmbiosHandle;
    727   EFI_SMBIOS_PROTOCOL               *Smbios;
    728   SMBIOS_TABLE_TYPE0                *Type0Record;
    729   SMBIOS_TABLE_TYPE1                *Type1Record;
    730   SMBIOS_TABLE_TYPE4                *Type4Record;
    731   SMBIOS_TABLE_TYPE19               *Type19Record;
    732   EFI_SMBIOS_TABLE_HEADER           *Record;
    733 
    734   ZeroMem (Find, sizeof (Find));
    735 
    736   //
    737   // Update Front Page strings
    738   //
    739   Status = gBS->LocateProtocol (
    740                   &gEfiSmbiosProtocolGuid,
    741                   NULL,
    742                   (VOID **) &Smbios
    743                   );
    744   if (!EFI_ERROR (Status)) {
    745     SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    746     do {
    747       Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
    748       if (EFI_ERROR(Status)) {
    749         break;
    750       }
    751 
    752       if (Record->Type == EFI_SMBIOS_TYPE_BIOS_INFORMATION) {
    753         Type0Record = (SMBIOS_TABLE_TYPE0 *) Record;
    754         StrIndex = Type0Record->BiosVersion;
    755         GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type0Record + Type0Record->Hdr.Length), StrIndex, &NewString);
    756         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION);
    757         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
    758         FreePool (NewString);
    759         Find[0] = TRUE;
    760       }
    761 
    762       if (Record->Type == EFI_SMBIOS_TYPE_SYSTEM_INFORMATION) {
    763         Type1Record = (SMBIOS_TABLE_TYPE1 *) Record;
    764         StrIndex = Type1Record->ProductName;
    765         GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);
    766         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL);
    767         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
    768         FreePool (NewString);
    769         Find[1] = TRUE;
    770       }
    771 
    772       if (Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) {
    773         Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
    774         StrIndex = Type4Record->ProcessorVersion;
    775         GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString);
    776         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL);
    777         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
    778         FreePool (NewString);
    779         Find[2] = TRUE;
    780       }
    781 
    782       if (Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) {
    783         Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
    784         ConvertProcessorToString(Type4Record->CurrentSpeed, 6, &NewString);
    785         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED);
    786         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
    787         FreePool (NewString);
    788         Find[3] = TRUE;
    789       }
    790 
    791       if ( Record->Type == EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS ) {
    792         Type19Record = (SMBIOS_TABLE_TYPE19 *) Record;
    793         ConvertMemorySizeToString (
    794           (UINT32)(RShiftU64((Type19Record->EndingAddress - Type19Record->StartingAddress + 1), 10)),
    795           &NewString
    796           );
    797         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE);
    798         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
    799         FreePool (NewString);
    800         Find[4] = TRUE;
    801       }
    802     } while ( !(Find[0] && Find[1] && Find[2] && Find[3] && Find[4]));
    803   }
    804   return ;
    805 }
    806 
    807 
    808 /**
    809   Function waits for a given event to fire, or for an optional timeout to expire.
    810 
    811   @param   Event              The event to wait for
    812   @param   Timeout            An optional timeout value in 100 ns units.
    813 
    814   @retval  EFI_SUCCESS      Event fired before Timeout expired.
    815   @retval  EFI_TIME_OUT     Timout expired before Event fired..
    816 
    817 **/
    818 EFI_STATUS
    819 WaitForSingleEvent (
    820   IN EFI_EVENT                  Event,
    821   IN UINT64                     Timeout OPTIONAL
    822   )
    823 {
    824   UINTN       Index;
    825   EFI_STATUS  Status;
    826   EFI_EVENT   TimerEvent;
    827   EFI_EVENT   WaitList[2];
    828 
    829   if (Timeout != 0) {
    830     //
    831     // Create a timer event
    832     //
    833     Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
    834     if (!EFI_ERROR (Status)) {
    835       //
    836       // Set the timer event
    837       //
    838       gBS->SetTimer (
    839              TimerEvent,
    840              TimerRelative,
    841              Timeout
    842              );
    843 
    844       //
    845       // Wait for the original event or the timer
    846       //
    847       WaitList[0] = Event;
    848       WaitList[1] = TimerEvent;
    849       Status      = gBS->WaitForEvent (2, WaitList, &Index);
    850       gBS->CloseEvent (TimerEvent);
    851 
    852       //
    853       // If the timer expired, change the return to timed out
    854       //
    855       if (!EFI_ERROR (Status) && Index == 1) {
    856         Status = EFI_TIMEOUT;
    857       }
    858     }
    859   } else {
    860     //
    861     // No timeout... just wait on the event
    862     //
    863     Status = gBS->WaitForEvent (1, &Event, &Index);
    864     ASSERT (!EFI_ERROR (Status));
    865     ASSERT (Index == 0);
    866   }
    867 
    868   return Status;
    869 }
    870 
    871 /**
    872   Function show progress bar to wait for user input.
    873 
    874 
    875   @param   TimeoutDefault  The fault time out value before the system continue to boot.
    876 
    877   @retval  EFI_SUCCESS       User pressed some key except "Enter"
    878   @retval  EFI_TIME_OUT      Timeout expired or user press "Enter"
    879 
    880 **/
    881 EFI_STATUS
    882 ShowProgress (
    883   IN UINT16                       TimeoutDefault
    884   )
    885 {
    886   CHAR16                        *TmpStr;
    887   UINT16                        TimeoutRemain;
    888   EFI_STATUS                    Status;
    889   EFI_INPUT_KEY                 Key;
    890   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
    891   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
    892   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
    893 
    894   if (TimeoutDefault != 0) {
    895     DEBUG ((EFI_D_INFO, "\n\nStart showing progress bar... Press any key to stop it! ...Zzz....\n"));
    896 
    897     SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
    898     SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
    899     SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
    900 
    901     TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION));
    902 
    903     if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
    904       //
    905       // Clear the progress status bar first
    906       //
    907       if (TmpStr != NULL) {
    908         PlatformBdsShowProgress (Foreground, Background, TmpStr, Color, 0, 0);
    909       }
    910     }
    911 
    912 
    913     TimeoutRemain = TimeoutDefault;
    914     while (TimeoutRemain != 0) {
    915       DEBUG ((EFI_D_INFO, "Showing progress bar...Remaining %d second!\n", TimeoutRemain));
    916 
    917       Status = WaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);
    918       if (Status != EFI_TIMEOUT) {
    919         break;
    920       }
    921       TimeoutRemain--;
    922 
    923       if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
    924         //
    925         // Show progress
    926         //
    927         if (TmpStr != NULL) {
    928           PlatformBdsShowProgress (
    929             Foreground,
    930             Background,
    931             TmpStr,
    932             Color,
    933             ((TimeoutDefault - TimeoutRemain) * 100 / TimeoutDefault),
    934             0
    935             );
    936         }
    937       }
    938     }
    939 
    940     if (TmpStr != NULL) {
    941       gBS->FreePool (TmpStr);
    942     }
    943 
    944     //
    945     // Timeout expired
    946     //
    947     if (TimeoutRemain == 0) {
    948       return EFI_TIMEOUT;
    949     }
    950   }
    951 
    952   //
    953   // User pressed some key
    954   //
    955   if (!PcdGetBool (PcdConInConnectOnDemand)) {
    956     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    957     if (EFI_ERROR (Status)) {
    958       return Status;
    959     }
    960 
    961     if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
    962       //
    963       // User pressed enter, equivalent to select "continue"
    964       //
    965       return EFI_TIMEOUT;
    966     }
    967   }
    968 
    969   return EFI_SUCCESS;
    970 }
    971 
    972 /**
    973   This function is the main entry of the platform setup entry.
    974   The function will present the main menu of the system setup,
    975   this is the platform reference part and can be customize.
    976 
    977 
    978   @param TimeoutDefault     The fault time out value before the system
    979                             continue to boot.
    980   @param ConnectAllHappened The indicater to check if the connect all have
    981                             already happened.
    982 
    983 **/
    984 VOID
    985 PlatformBdsEnterFrontPage (
    986   IN UINT16                       TimeoutDefault,
    987   IN BOOLEAN                      ConnectAllHappened
    988   )
    989 {
    990   EFI_STATUS                         Status;
    991   EFI_STATUS                         StatusHotkey;
    992   EFI_BOOT_LOGO_PROTOCOL             *BootLogo;
    993   EFI_GRAPHICS_OUTPUT_PROTOCOL       *GraphicsOutput;
    994   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *SimpleTextOut;
    995   UINTN                              BootTextColumn;
    996   UINTN                              BootTextRow;
    997   UINT64                             OsIndication;
    998   UINTN                              DataSize;
    999   EFI_INPUT_KEY                      Key;
   1000 
   1001   GraphicsOutput = NULL;
   1002   SimpleTextOut = NULL;
   1003 
   1004   PERF_START (NULL, "BdsTimeOut", "BDS", 0);
   1005   //
   1006   // Indicate if we need connect all in the platform setup
   1007   //
   1008   if (ConnectAllHappened) {
   1009     gConnectAllHappened = TRUE;
   1010   }
   1011 
   1012   if (!mModeInitialized) {
   1013     //
   1014     // After the console is ready, get current video resolution
   1015     // and text mode before launching setup at first time.
   1016     //
   1017     Status = gBS->HandleProtocol (
   1018                     gST->ConsoleOutHandle,
   1019                     &gEfiGraphicsOutputProtocolGuid,
   1020                     (VOID**)&GraphicsOutput
   1021                     );
   1022     if (EFI_ERROR (Status)) {
   1023       GraphicsOutput = NULL;
   1024     }
   1025 
   1026     Status = gBS->HandleProtocol (
   1027                     gST->ConsoleOutHandle,
   1028                     &gEfiSimpleTextOutProtocolGuid,
   1029                     (VOID**)&SimpleTextOut
   1030                     );
   1031     if (EFI_ERROR (Status)) {
   1032       SimpleTextOut = NULL;
   1033     }
   1034 
   1035     if (GraphicsOutput != NULL) {
   1036       //
   1037       // Get current video resolution and text mode.
   1038       //
   1039       mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
   1040       mBootVerticalResolution   = GraphicsOutput->Mode->Info->VerticalResolution;
   1041     }
   1042 
   1043     if (SimpleTextOut != NULL) {
   1044       Status = SimpleTextOut->QueryMode (
   1045                                 SimpleTextOut,
   1046                                 SimpleTextOut->Mode->Mode,
   1047                                 &BootTextColumn,
   1048                                 &BootTextRow
   1049                                 );
   1050       mBootTextModeColumn = (UINT32)BootTextColumn;
   1051       mBootTextModeRow    = (UINT32)BootTextRow;
   1052     }
   1053 
   1054     //
   1055     // Get user defined text mode for setup.
   1056     //
   1057     mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
   1058     mSetupVerticalResolution   = PcdGet32 (PcdSetupVideoVerticalResolution);
   1059     mSetupTextModeColumn       = PcdGet32 (PcdSetupConOutColumn);
   1060     mSetupTextModeRow          = PcdGet32 (PcdSetupConOutRow);
   1061 
   1062     mModeInitialized           = TRUE;
   1063   }
   1064 
   1065 
   1066   //
   1067   // goto FrontPage directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set
   1068   //
   1069   OsIndication = 0;
   1070   DataSize = sizeof(UINT64);
   1071   Status = gRT->GetVariable (
   1072                   L"OsIndications",
   1073                   &gEfiGlobalVariableGuid,
   1074                   NULL,
   1075                   &DataSize,
   1076                   &OsIndication
   1077                   );
   1078 
   1079   //
   1080   // goto FrontPage directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
   1081   //
   1082   if (!EFI_ERROR(Status) && ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0)) {
   1083     //
   1084     // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
   1085     //
   1086     OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
   1087     Status = gRT->SetVariable (
   1088                     L"OsIndications",
   1089                     &gEfiGlobalVariableGuid,
   1090                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1091                     sizeof(UINT64),
   1092                     &OsIndication
   1093                     );
   1094     //
   1095     // Changing the content without increasing its size with current variable implementation shouldn't fail.
   1096     //
   1097     ASSERT_EFI_ERROR (Status);
   1098 
   1099     //
   1100     // Follow generic rule, Call ReadKeyStroke to connect ConIn before enter UI
   1101     //
   1102     if (PcdGetBool (PcdConInConnectOnDemand)) {
   1103       gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
   1104     }
   1105 
   1106     //
   1107     // Ensure screen is clear when switch Console from Graphics mode to Text mode
   1108     //
   1109     gST->ConOut->EnableCursor (gST->ConOut, TRUE);
   1110     gST->ConOut->ClearScreen (gST->ConOut);
   1111 
   1112   } else {
   1113 
   1114     HotkeyBoot ();
   1115     if (TimeoutDefault != 0xffff) {
   1116       Status = ShowProgress (TimeoutDefault);
   1117       StatusHotkey = HotkeyBoot ();
   1118 
   1119       if (!FeaturePcdGet(PcdBootlogoOnlyEnable) || !EFI_ERROR(Status) || !EFI_ERROR(StatusHotkey)){
   1120         //
   1121         // Ensure screen is clear when switch Console from Graphics mode to Text mode
   1122         // Skip it in normal boot
   1123         //
   1124         gST->ConOut->EnableCursor (gST->ConOut, TRUE);
   1125         gST->ConOut->ClearScreen (gST->ConOut);
   1126       }
   1127 
   1128       if (EFI_ERROR (Status)) {
   1129         //
   1130         // Timeout or user press enter to continue
   1131         //
   1132         goto Exit;
   1133       }
   1134     }
   1135   }
   1136 
   1137   //
   1138   // Boot Logo is corrupted, report it using Boot Logo protocol.
   1139   //
   1140   Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
   1141   if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
   1142     BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
   1143   }
   1144 
   1145   //
   1146   // Install BM HiiPackages.
   1147   // Keep BootMaint HiiPackage, so that it can be covered by global setting.
   1148   //
   1149   InitBMPackage ();
   1150 
   1151   Status = EFI_SUCCESS;
   1152   do {
   1153     //
   1154     // Set proper video resolution and text mode for setup
   1155     //
   1156     BdsSetConsoleMode (TRUE);
   1157 
   1158     InitializeFrontPage (FALSE);
   1159 
   1160     //
   1161     // Update Front Page strings
   1162     //
   1163     UpdateFrontPageStrings ();
   1164 
   1165     gCallbackKey = 0;
   1166     CallFrontPage ();
   1167 
   1168     //
   1169     // If gCallbackKey is greater than 1 and less or equal to 5,
   1170     // it will launch configuration utilities.
   1171     // 2 = set language
   1172     // 3 = boot manager
   1173     // 4 = device manager
   1174     // 5 = boot maintenance manager
   1175     //
   1176     if (gCallbackKey != 0) {
   1177       REPORT_STATUS_CODE (
   1178         EFI_PROGRESS_CODE,
   1179         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP)
   1180         );
   1181     }
   1182     //
   1183     // Based on the key that was set, we can determine what to do
   1184     //
   1185     switch (gCallbackKey) {
   1186     //
   1187     // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can
   1188     // describe to their customers in documentation how to find their setup information (namely
   1189     // under the device manager and specific buckets)
   1190     //
   1191     // These entries consist of the Continue, Select language, Boot Manager, and Device Manager
   1192     //
   1193     case FRONT_PAGE_KEY_CONTINUE:
   1194       //
   1195       // User hit continue
   1196       //
   1197       break;
   1198 
   1199     case FRONT_PAGE_KEY_LANGUAGE:
   1200       //
   1201       // User made a language setting change - display front page again
   1202       //
   1203       break;
   1204 
   1205     case FRONT_PAGE_KEY_BOOT_MANAGER:
   1206       //
   1207       // Remove the installed BootMaint HiiPackages when exit.
   1208       //
   1209       FreeBMPackage ();
   1210 
   1211       //
   1212       // User chose to run the Boot Manager
   1213       //
   1214       CallBootManager ();
   1215 
   1216       //
   1217       // Reinstall BootMaint HiiPackages after exiting from Boot Manager.
   1218       //
   1219       InitBMPackage ();
   1220       break;
   1221 
   1222     case FRONT_PAGE_KEY_DEVICE_MANAGER:
   1223       //
   1224       // Display the Device Manager
   1225       //
   1226       do {
   1227         CallDeviceManager ();
   1228       } while (gCallbackKey == FRONT_PAGE_KEY_DEVICE_MANAGER);
   1229       break;
   1230 
   1231     case FRONT_PAGE_KEY_BOOT_MAINTAIN:
   1232       //
   1233       // Display the Boot Maintenance Manager
   1234       //
   1235       BdsStartBootMaint ();
   1236       break;
   1237     }
   1238 
   1239   } while ((Status == EFI_SUCCESS) && (gCallbackKey != FRONT_PAGE_KEY_CONTINUE));
   1240 
   1241   if (mLanguageString != NULL) {
   1242     FreePool (mLanguageString);
   1243     mLanguageString = NULL;
   1244   }
   1245   //
   1246   //Will leave browser, check any reset required change is applied? if yes, reset system
   1247   //
   1248   SetupResetReminder ();
   1249 
   1250   //
   1251   // Remove the installed BootMaint HiiPackages when exit.
   1252   //
   1253   FreeBMPackage ();
   1254 
   1255 Exit:
   1256   //
   1257   // Automatically load current entry
   1258   // Note: The following lines of code only execute when Auto boot
   1259   // takes affect
   1260   //
   1261   PERF_END (NULL, "BdsTimeOut", "BDS", 0);
   1262 }
   1263 
   1264 /**
   1265   This function will change video resolution and text mode
   1266   according to defined setup mode or defined boot mode
   1267 
   1268   @param  IsSetupMode   Indicate mode is changed to setup mode or boot mode.
   1269 
   1270   @retval  EFI_SUCCESS  Mode is changed successfully.
   1271   @retval  Others             Mode failed to be changed.
   1272 
   1273 **/
   1274 EFI_STATUS
   1275 EFIAPI
   1276 BdsSetConsoleMode (
   1277   BOOLEAN  IsSetupMode
   1278   )
   1279 {
   1280   EFI_GRAPHICS_OUTPUT_PROTOCOL          *GraphicsOutput;
   1281   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL       *SimpleTextOut;
   1282   UINTN                                 SizeOfInfo;
   1283   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
   1284   UINT32                                MaxGopMode;
   1285   UINT32                                MaxTextMode;
   1286   UINT32                                ModeNumber;
   1287   UINT32                                NewHorizontalResolution;
   1288   UINT32                                NewVerticalResolution;
   1289   UINT32                                NewColumns;
   1290   UINT32                                NewRows;
   1291   UINTN                                 HandleCount;
   1292   EFI_HANDLE                            *HandleBuffer;
   1293   EFI_STATUS                            Status;
   1294   UINTN                                 Index;
   1295   UINTN                                 CurrentColumn;
   1296   UINTN                                 CurrentRow;
   1297 
   1298   MaxGopMode  = 0;
   1299   MaxTextMode = 0;
   1300 
   1301   //
   1302   // Get current video resolution and text mode
   1303   //
   1304   Status = gBS->HandleProtocol (
   1305                   gST->ConsoleOutHandle,
   1306                   &gEfiGraphicsOutputProtocolGuid,
   1307                   (VOID**)&GraphicsOutput
   1308                   );
   1309   if (EFI_ERROR (Status)) {
   1310     GraphicsOutput = NULL;
   1311   }
   1312 
   1313   Status = gBS->HandleProtocol (
   1314                   gST->ConsoleOutHandle,
   1315                   &gEfiSimpleTextOutProtocolGuid,
   1316                   (VOID**)&SimpleTextOut
   1317                   );
   1318   if (EFI_ERROR (Status)) {
   1319     SimpleTextOut = NULL;
   1320   }
   1321 
   1322   if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
   1323     return EFI_UNSUPPORTED;
   1324   }
   1325 
   1326   if (IsSetupMode) {
   1327     //
   1328     // The requried resolution and text mode is setup mode.
   1329     //
   1330     NewHorizontalResolution = mSetupHorizontalResolution;
   1331     NewVerticalResolution   = mSetupVerticalResolution;
   1332     NewColumns              = mSetupTextModeColumn;
   1333     NewRows                 = mSetupTextModeRow;
   1334   } else {
   1335     //
   1336     // The required resolution and text mode is boot mode.
   1337     //
   1338     NewHorizontalResolution = mBootHorizontalResolution;
   1339     NewVerticalResolution   = mBootVerticalResolution;
   1340     NewColumns              = mBootTextModeColumn;
   1341     NewRows                 = mBootTextModeRow;
   1342   }
   1343 
   1344   if (GraphicsOutput != NULL) {
   1345     MaxGopMode  = GraphicsOutput->Mode->MaxMode;
   1346   }
   1347 
   1348   if (SimpleTextOut != NULL) {
   1349     MaxTextMode = SimpleTextOut->Mode->MaxMode;
   1350   }
   1351 
   1352   //
   1353   // 1. If current video resolution is same with required video resolution,
   1354   //    video resolution need not be changed.
   1355   //    1.1. If current text mode is same with required text mode, text mode need not be changed.
   1356   //    1.2. If current text mode is different from required text mode, text mode need be changed.
   1357   // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.
   1358   //
   1359   for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
   1360     Status = GraphicsOutput->QueryMode (
   1361                        GraphicsOutput,
   1362                        ModeNumber,
   1363                        &SizeOfInfo,
   1364                        &Info
   1365                        );
   1366     if (!EFI_ERROR (Status)) {
   1367       if ((Info->HorizontalResolution == NewHorizontalResolution) &&
   1368           (Info->VerticalResolution == NewVerticalResolution)) {
   1369         if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&
   1370             (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {
   1371           //
   1372           // Current resolution is same with required resolution, check if text mode need be set
   1373           //
   1374           Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
   1375           ASSERT_EFI_ERROR (Status);
   1376           if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
   1377             //
   1378             // If current text mode is same with required text mode. Do nothing
   1379             //
   1380             FreePool (Info);
   1381             return EFI_SUCCESS;
   1382           } else {
   1383             //
   1384             // If current text mode is different from requried text mode.  Set new video mode
   1385             //
   1386             for (Index = 0; Index < MaxTextMode; Index++) {
   1387               Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
   1388               if (!EFI_ERROR(Status)) {
   1389                 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
   1390                   //
   1391                   // Required text mode is supported, set it.
   1392                   //
   1393                   Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
   1394                   ASSERT_EFI_ERROR (Status);
   1395                   //
   1396                   // Update text mode PCD.
   1397                   //
   1398                   Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn);
   1399                   ASSERT_EFI_ERROR (Status);
   1400                   Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow);
   1401                   ASSERT_EFI_ERROR (Status);
   1402                   FreePool (Info);
   1403                   return EFI_SUCCESS;
   1404                 }
   1405               }
   1406             }
   1407             if (Index == MaxTextMode) {
   1408               //
   1409               // If requried text mode is not supported, return error.
   1410               //
   1411               FreePool (Info);
   1412               return EFI_UNSUPPORTED;
   1413             }
   1414           }
   1415         } else {
   1416           //
   1417           // If current video resolution is not same with the new one, set new video resolution.
   1418           // In this case, the driver which produces simple text out need be restarted.
   1419           //
   1420           Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
   1421           if (!EFI_ERROR (Status)) {
   1422             FreePool (Info);
   1423             break;
   1424           }
   1425         }
   1426       }
   1427       FreePool (Info);
   1428     }
   1429   }
   1430 
   1431   if (ModeNumber == MaxGopMode) {
   1432     //
   1433     // If the resolution is not supported, return error.
   1434     //
   1435     return EFI_UNSUPPORTED;
   1436   }
   1437 
   1438   //
   1439   // Set PCD to Inform GraphicsConsole to change video resolution.
   1440   // Set PCD to Inform Consplitter to change text mode.
   1441   //
   1442   Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);
   1443   ASSERT_EFI_ERROR (Status);
   1444   Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);
   1445   ASSERT_EFI_ERROR (Status);
   1446   Status = PcdSet32S (PcdConOutColumn, NewColumns);
   1447   ASSERT_EFI_ERROR (Status);
   1448   Status = PcdSet32S (PcdConOutRow, NewRows);
   1449   ASSERT_EFI_ERROR (Status);
   1450 
   1451 
   1452   //
   1453   // Video mode is changed, so restart graphics console driver and higher level driver.
   1454   // Reconnect graphics console driver and higher level driver.
   1455   // Locate all the handles with GOP protocol and reconnect it.
   1456   //
   1457   Status = gBS->LocateHandleBuffer (
   1458                    ByProtocol,
   1459                    &gEfiSimpleTextOutProtocolGuid,
   1460                    NULL,
   1461                    &HandleCount,
   1462                    &HandleBuffer
   1463                    );
   1464   if (!EFI_ERROR (Status)) {
   1465     for (Index = 0; Index < HandleCount; Index++) {
   1466       gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
   1467     }
   1468     for (Index = 0; Index < HandleCount; Index++) {
   1469       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
   1470     }
   1471     if (HandleBuffer != NULL) {
   1472       FreePool (HandleBuffer);
   1473     }
   1474   }
   1475 
   1476   return EFI_SUCCESS;
   1477 }
   1478 
   1479