Home | History | Annotate | Download | only in BdsDxe
      1 /** @file
      2   FrontPage routines to handle the callbacks and browser calls
      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 "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   UINTN                       LangSize;
    304   CHAR8                       *CurrentLang;
    305   UINTN                       OptionCount;
    306   CHAR16                      *StringBuffer;
    307   EFI_HII_HANDLE              HiiHandle;
    308   VOID                        *OptionsOpCodeHandle;
    309   VOID                        *StartOpCodeHandle;
    310   VOID                        *EndOpCodeHandle;
    311   EFI_IFR_GUID_LABEL          *StartLabel;
    312   EFI_IFR_GUID_LABEL          *EndLabel;
    313   EFI_HII_STRING_PROTOCOL     *HiiString;
    314   UINTN                       StringSize;
    315 
    316   Lang         = NULL;
    317   StringBuffer = NULL;
    318 
    319   if (InitializeHiiData) {
    320     //
    321     // Initialize the Device Manager
    322     //
    323     InitializeDeviceManager ();
    324 
    325     //
    326     // Initialize the Device Manager
    327     //
    328     InitializeBootManager ();
    329 
    330     gCallbackKey  = 0;
    331 
    332     //
    333     // Locate Hii relative protocols
    334     //
    335     Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFormBrowser2);
    336     if (EFI_ERROR (Status)) {
    337       return Status;
    338     }
    339 
    340     //
    341     // Install Device Path Protocol and Config Access protocol to driver handle
    342     //
    343     Status = gBS->InstallMultipleProtocolInterfaces (
    344                     &gFrontPagePrivate.DriverHandle,
    345                     &gEfiDevicePathProtocolGuid,
    346                     &mFrontPageHiiVendorDevicePath,
    347                     &gEfiHiiConfigAccessProtocolGuid,
    348                     &gFrontPagePrivate.ConfigAccess,
    349                     NULL
    350                     );
    351     ASSERT_EFI_ERROR (Status);
    352 
    353     //
    354     // Publish our HII data
    355     //
    356     gFrontPagePrivate.HiiHandle = HiiAddPackages (
    357                                     &gFrontPageFormSetGuid,
    358                                     gFrontPagePrivate.DriverHandle,
    359                                     FrontPageVfrBin,
    360                                     BdsDxeStrings,
    361                                     NULL
    362                                     );
    363     if (gFrontPagePrivate.HiiHandle == NULL) {
    364       return EFI_OUT_OF_RESOURCES;
    365     }
    366   }
    367 
    368 
    369   //
    370   // Init OpCode Handle and Allocate space for creation of UpdateData Buffer
    371   //
    372   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
    373   ASSERT (StartOpCodeHandle != NULL);
    374 
    375   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
    376   ASSERT (EndOpCodeHandle != NULL);
    377 
    378   OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
    379   ASSERT (OptionsOpCodeHandle != NULL);
    380   //
    381   // Create Hii Extend Label OpCode as the start opcode
    382   //
    383   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    384   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    385   StartLabel->Number       = LABEL_SELECT_LANGUAGE;
    386 
    387   //
    388   // Create Hii Extend Label OpCode as the end opcode
    389   //
    390   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    391   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    392   EndLabel->Number       = LABEL_END;
    393 
    394   //
    395   // Collect the languages from what our current Language support is based on our VFR
    396   //
    397   HiiHandle = gFrontPagePrivate.HiiHandle;
    398 
    399   GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL);
    400 
    401   //
    402   // Get Support language list from variable.
    403   //
    404   if (mLanguageString == NULL){
    405     GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&mLanguageString, NULL);
    406     if (mLanguageString == NULL) {
    407       mLanguageString = AllocateCopyPool (
    408                                  AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),
    409                                  (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)
    410                                  );
    411       ASSERT (mLanguageString != NULL);
    412     }
    413   }
    414 
    415   if (gFrontPagePrivate.LanguageToken == NULL) {
    416     //
    417     // Count the language list number.
    418     //
    419     LangCode      = mLanguageString;
    420     Lang          = AllocatePool (AsciiStrSize (mLanguageString));
    421     ASSERT (Lang != NULL);
    422     OptionCount = 0;
    423     while (*LangCode != 0) {
    424       GetNextLanguage (&LangCode, Lang);
    425       OptionCount ++;
    426     }
    427 
    428     //
    429     // Allocate extra 1 as the end tag.
    430     //
    431     gFrontPagePrivate.LanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID));
    432     ASSERT (gFrontPagePrivate.LanguageToken != NULL);
    433 
    434     Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
    435     ASSERT_EFI_ERROR (Status);
    436 
    437     LangCode     = mLanguageString;
    438     OptionCount  = 0;
    439     while (*LangCode != 0) {
    440       GetNextLanguage (&LangCode, Lang);
    441 
    442       StringSize = 0;
    443       Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
    444       if (Status == EFI_BUFFER_TOO_SMALL) {
    445         StringBuffer = AllocateZeroPool (StringSize);
    446         ASSERT (StringBuffer != NULL);
    447         Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
    448         ASSERT_EFI_ERROR (Status);
    449       }
    450 
    451       if (EFI_ERROR (Status)) {
    452         LangSize = AsciiStrSize (Lang);
    453         StringBuffer = AllocatePool (LangSize * sizeof (CHAR16));
    454         ASSERT (StringBuffer != NULL);
    455         AsciiStrToUnicodeStrS (Lang, StringBuffer, LangSize);
    456       }
    457 
    458       ASSERT (StringBuffer != NULL);
    459       gFrontPagePrivate.LanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);
    460       FreePool (StringBuffer);
    461 
    462       OptionCount++;
    463     }
    464   }
    465 
    466   ASSERT (gFrontPagePrivate.LanguageToken != NULL);
    467   LangCode     = mLanguageString;
    468   OptionCount  = 0;
    469   if (Lang == NULL) {
    470     Lang = AllocatePool (AsciiStrSize (mLanguageString));
    471     ASSERT (Lang != NULL);
    472   }
    473   while (*LangCode != 0) {
    474     GetNextLanguage (&LangCode, Lang);
    475 
    476     if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) {
    477       HiiCreateOneOfOptionOpCode (
    478         OptionsOpCodeHandle,
    479         gFrontPagePrivate.LanguageToken[OptionCount],
    480         EFI_IFR_OPTION_DEFAULT,
    481         EFI_IFR_NUMERIC_SIZE_1,
    482         (UINT8) OptionCount
    483         );
    484     } else {
    485       HiiCreateOneOfOptionOpCode (
    486         OptionsOpCodeHandle,
    487         gFrontPagePrivate.LanguageToken[OptionCount],
    488         0,
    489         EFI_IFR_NUMERIC_SIZE_1,
    490         (UINT8) OptionCount
    491         );
    492     }
    493 
    494     OptionCount++;
    495   }
    496 
    497   if (CurrentLang != NULL) {
    498     FreePool (CurrentLang);
    499   }
    500   FreePool (Lang);
    501 
    502   HiiCreateOneOfOpCode (
    503     StartOpCodeHandle,
    504     FRONT_PAGE_KEY_LANGUAGE,
    505     0,
    506     0,
    507     STRING_TOKEN (STR_LANGUAGE_SELECT),
    508     STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),
    509     EFI_IFR_FLAG_CALLBACK,
    510     EFI_IFR_NUMERIC_SIZE_1,
    511     OptionsOpCodeHandle,
    512     NULL
    513     );
    514 
    515   Status = HiiUpdateForm (
    516              HiiHandle,
    517              &gFrontPageFormSetGuid,
    518              FRONT_PAGE_FORM_ID,
    519              StartOpCodeHandle, // LABEL_SELECT_LANGUAGE
    520              EndOpCodeHandle    // LABEL_END
    521              );
    522 
    523   HiiFreeOpCodeHandle (StartOpCodeHandle);
    524   HiiFreeOpCodeHandle (EndOpCodeHandle);
    525   HiiFreeOpCodeHandle (OptionsOpCodeHandle);
    526   return Status;
    527 }
    528 
    529 /**
    530   Call the browser and display the front page
    531 
    532   @return   Status code that will be returned by
    533             EFI_FORM_BROWSER2_PROTOCOL.SendForm ().
    534 
    535 **/
    536 EFI_STATUS
    537 CallFrontPage (
    538   VOID
    539   )
    540 {
    541   EFI_STATUS                  Status;
    542   EFI_BROWSER_ACTION_REQUEST  ActionRequest;
    543 
    544   //
    545   // Begin waiting for USER INPUT
    546   //
    547   REPORT_STATUS_CODE (
    548     EFI_PROGRESS_CODE,
    549     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_INPUT_WAIT)
    550     );
    551 
    552   ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
    553   Status = gFormBrowser2->SendForm (
    554                             gFormBrowser2,
    555                             &gFrontPagePrivate.HiiHandle,
    556                             1,
    557                             &gFrontPageFormSetGuid,
    558                             0,
    559                             NULL,
    560                             &ActionRequest
    561                             );
    562   //
    563   // Check whether user change any option setting which needs a reset to be effective
    564   //
    565   if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
    566     EnableResetRequired ();
    567   }
    568 
    569   return Status;
    570 }
    571 
    572 /**
    573   Acquire the string associated with the ProducerGuid and return it.
    574 
    575 
    576   @param ProducerGuid    The Guid to search the HII database for
    577   @param Token           The token value of the string to extract
    578   @param String          The string that is extracted
    579 
    580   @retval  EFI_SUCCESS  The function returns EFI_SUCCESS always.
    581 
    582 **/
    583 EFI_STATUS
    584 GetProducerString (
    585   IN      EFI_GUID                  *ProducerGuid,
    586   IN      EFI_STRING_ID             Token,
    587   OUT     CHAR16                    **String
    588   )
    589 {
    590   EFI_STRING      TmpString;
    591 
    592   TmpString = HiiGetPackageString (ProducerGuid, Token, NULL);
    593   if (TmpString == NULL) {
    594     *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));
    595   } else {
    596     *String = TmpString;
    597   }
    598 
    599   return EFI_SUCCESS;
    600 }
    601 
    602 /**
    603   Convert Processor Frequency Data to a string.
    604 
    605   @param ProcessorFrequency The frequency data to process
    606   @param Base10Exponent     The exponent based on 10
    607   @param String             The string that is created
    608 
    609 **/
    610 VOID
    611 ConvertProcessorToString (
    612   IN  UINT16                               ProcessorFrequency,
    613   IN  UINT16                               Base10Exponent,
    614   OUT CHAR16                               **String
    615   )
    616 {
    617   CHAR16  *StringBuffer;
    618   UINTN   Index;
    619   UINT32  FreqMhz;
    620 
    621   if (Base10Exponent >= 6) {
    622     FreqMhz = ProcessorFrequency;
    623     for (Index = 0; Index < (UINTN) (Base10Exponent - 6); Index++) {
    624       FreqMhz *= 10;
    625     }
    626   } else {
    627     FreqMhz = 0;
    628   }
    629 
    630   StringBuffer = AllocateZeroPool (0x20);
    631   ASSERT (StringBuffer != NULL);
    632   Index = UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, FreqMhz / 1000, 3);
    633   StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L".");
    634   UnicodeValueToString (StringBuffer + Index + 1, PREFIX_ZERO, (FreqMhz % 1000) / 10, 2);
    635   StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L" GHz");
    636   *String = (CHAR16 *) StringBuffer;
    637   return ;
    638 }
    639 
    640 
    641 /**
    642   Convert Memory Size to a string.
    643 
    644   @param MemorySize      The size of the memory to process
    645   @param String          The string that is created
    646 
    647 **/
    648 VOID
    649 ConvertMemorySizeToString (
    650   IN  UINT32          MemorySize,
    651   OUT CHAR16          **String
    652   )
    653 {
    654   CHAR16  *StringBuffer;
    655 
    656   StringBuffer = AllocateZeroPool (0x20);
    657   ASSERT (StringBuffer != NULL);
    658   UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, MemorySize, 6);
    659   StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L" MB RAM");
    660 
    661   *String = (CHAR16 *) StringBuffer;
    662 
    663   return ;
    664 }
    665 
    666 /**
    667 
    668   Acquire the string associated with the Index from smbios structure and return it.
    669   The caller is responsible for free the string buffer.
    670 
    671   @param    OptionalStrStart  The start position to search the string
    672   @param    Index             The index of the string to extract
    673   @param    String            The string that is extracted
    674 
    675   @retval   EFI_SUCCESS       The function returns EFI_SUCCESS always.
    676 
    677 **/
    678 EFI_STATUS
    679 GetOptionalStringByIndex (
    680   IN      CHAR8                   *OptionalStrStart,
    681   IN      UINT8                   Index,
    682   OUT     CHAR16                  **String
    683   )
    684 {
    685   UINTN          StrSize;
    686 
    687   if (Index == 0) {
    688     *String = AllocateZeroPool (sizeof (CHAR16));
    689     return EFI_SUCCESS;
    690   }
    691 
    692   StrSize = 0;
    693   do {
    694     Index--;
    695     OptionalStrStart += StrSize;
    696     StrSize           = AsciiStrSize (OptionalStrStart);
    697   } while (OptionalStrStart[StrSize] != 0 && Index != 0);
    698 
    699   if ((Index != 0) || (StrSize == 1)) {
    700     //
    701     // Meet the end of strings set but Index is non-zero, or
    702     // Find an empty string
    703     //
    704     *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));
    705   } else {
    706     *String = AllocatePool (StrSize * sizeof (CHAR16));
    707     AsciiStrToUnicodeStrS (OptionalStrStart, *String, StrSize);
    708   }
    709 
    710   return EFI_SUCCESS;
    711 }
    712 
    713 
    714 /**
    715   Update the banner information for the Front Page based on DataHub information.
    716 
    717 **/
    718 VOID
    719 UpdateFrontPageStrings (
    720   VOID
    721   )
    722 {
    723   UINT8                             StrIndex;
    724   CHAR16                            *NewString;
    725   EFI_STATUS                        Status;
    726   EFI_STRING_ID                     TokenToUpdate;
    727   EFI_SMBIOS_HANDLE                 SmbiosHandle;
    728   EFI_SMBIOS_PROTOCOL               *Smbios;
    729   SMBIOS_TABLE_TYPE0                *Type0Record;
    730   SMBIOS_TABLE_TYPE1                *Type1Record;
    731   SMBIOS_TABLE_TYPE4                *Type4Record;
    732   SMBIOS_TABLE_TYPE19               *Type19Record;
    733   EFI_SMBIOS_TABLE_HEADER           *Record;
    734   UINT64                            InstalledMemory;
    735 
    736   InstalledMemory = 0;
    737 
    738   //
    739   // Update Front Page strings
    740   //
    741   Status = gBS->LocateProtocol (
    742                   &gEfiSmbiosProtocolGuid,
    743                   NULL,
    744                   (VOID **) &Smbios
    745                   );
    746   if (!EFI_ERROR (Status)) {
    747     SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
    748     Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
    749     while (!EFI_ERROR(Status)) {
    750       if (Record->Type == SMBIOS_TYPE_BIOS_INFORMATION) {
    751         Type0Record = (SMBIOS_TABLE_TYPE0 *) Record;
    752         StrIndex = Type0Record->BiosVersion;
    753         GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type0Record + Type0Record->Hdr.Length), StrIndex, &NewString);
    754         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION);
    755         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
    756         FreePool (NewString);
    757       }
    758 
    759       if (Record->Type == SMBIOS_TYPE_SYSTEM_INFORMATION) {
    760         Type1Record = (SMBIOS_TABLE_TYPE1 *) Record;
    761         StrIndex = Type1Record->ProductName;
    762         GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);
    763         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL);
    764         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
    765         FreePool (NewString);
    766       }
    767 
    768       if (Record->Type == SMBIOS_TYPE_PROCESSOR_INFORMATION) {
    769         Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
    770         StrIndex = Type4Record->ProcessorVersion;
    771         GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString);
    772         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL);
    773         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
    774         FreePool (NewString);
    775       }
    776 
    777       if (Record->Type == SMBIOS_TYPE_PROCESSOR_INFORMATION) {
    778         Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
    779         ConvertProcessorToString(Type4Record->CurrentSpeed, 6, &NewString);
    780         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED);
    781         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
    782         FreePool (NewString);
    783       }
    784 
    785       if ( Record->Type == SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS ) {
    786         Type19Record = (SMBIOS_TABLE_TYPE19 *) Record;
    787         if (Type19Record->StartingAddress != 0xFFFFFFFF ) {
    788           InstalledMemory += RShiftU64(Type19Record->EndingAddress -
    789                                        Type19Record->StartingAddress + 1, 10);
    790         } else {
    791           InstalledMemory += RShiftU64(Type19Record->ExtendedEndingAddress -
    792                                        Type19Record->ExtendedStartingAddress + 1, 20);
    793         }
    794       }
    795 
    796       Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
    797     }
    798 
    799     // now update the total installed RAM size
    800     ConvertMemorySizeToString ((UINT32)InstalledMemory, &NewString );
    801     TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE);
    802     HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
    803     FreePool (NewString);
    804   }
    805 
    806   return ;
    807 }
    808 
    809 
    810 /**
    811   Function waits for a given event to fire, or for an optional timeout to expire.
    812 
    813   @param   Event              The event to wait for
    814   @param   Timeout            An optional timeout value in 100 ns units.
    815 
    816   @retval  EFI_SUCCESS      Event fired before Timeout expired.
    817   @retval  EFI_TIME_OUT     Timout expired before Event fired..
    818 
    819 **/
    820 EFI_STATUS
    821 WaitForSingleEvent (
    822   IN EFI_EVENT                  Event,
    823   IN UINT64                     Timeout OPTIONAL
    824   )
    825 {
    826   UINTN       Index;
    827   EFI_STATUS  Status;
    828   EFI_EVENT   TimerEvent;
    829   EFI_EVENT   WaitList[2];
    830 
    831   if (Timeout != 0) {
    832     //
    833     // Create a timer event
    834     //
    835     Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
    836     if (!EFI_ERROR (Status)) {
    837       //
    838       // Set the timer event
    839       //
    840       gBS->SetTimer (
    841              TimerEvent,
    842              TimerRelative,
    843              Timeout
    844              );
    845 
    846       //
    847       // Wait for the original event or the timer
    848       //
    849       WaitList[0] = Event;
    850       WaitList[1] = TimerEvent;
    851       Status      = gBS->WaitForEvent (2, WaitList, &Index);
    852       gBS->CloseEvent (TimerEvent);
    853 
    854       //
    855       // If the timer expired, change the return to timed out
    856       //
    857       if (!EFI_ERROR (Status) && Index == 1) {
    858         Status = EFI_TIMEOUT;
    859       }
    860     }
    861   } else {
    862     //
    863     // No timeout... just wait on the event
    864     //
    865     Status = gBS->WaitForEvent (1, &Event, &Index);
    866     ASSERT (!EFI_ERROR (Status));
    867     ASSERT (Index == 0);
    868   }
    869 
    870   return Status;
    871 }
    872 
    873 /**
    874   Function show progress bar to wait for user input.
    875 
    876 
    877   @param   TimeoutDefault  The fault time out value before the system continue to boot.
    878 
    879   @retval  EFI_SUCCESS       User pressed some key except "Enter"
    880   @retval  EFI_TIME_OUT      Timeout expired or user press "Enter"
    881 
    882 **/
    883 EFI_STATUS
    884 ShowProgress (
    885   IN UINT16                       TimeoutDefault
    886   )
    887 {
    888   CHAR16                        *TmpStr;
    889   UINT16                        TimeoutRemain;
    890   EFI_STATUS                    Status;
    891   EFI_INPUT_KEY                 Key;
    892   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
    893   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
    894   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
    895 
    896   if (TimeoutDefault != 0) {
    897     DEBUG ((EFI_D_INFO, "\n\nStart showing progress bar... Press any key to stop it! ...Zzz....\n"));
    898 
    899     SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
    900     SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
    901     SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
    902 
    903     TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION));
    904 
    905     if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
    906       //
    907       // Clear the progress status bar first
    908       //
    909       if (TmpStr != NULL) {
    910         PlatformBdsShowProgress (Foreground, Background, TmpStr, Color, 0, 0);
    911       }
    912     }
    913 
    914 
    915     TimeoutRemain = TimeoutDefault;
    916     while (TimeoutRemain != 0) {
    917       DEBUG ((EFI_D_INFO, "Showing progress bar...Remaining %d second!\n", TimeoutRemain));
    918 
    919       Status = WaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);
    920       if (Status != EFI_TIMEOUT) {
    921         break;
    922       }
    923       TimeoutRemain--;
    924 
    925       if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
    926         //
    927         // Show progress
    928         //
    929         if (TmpStr != NULL) {
    930           PlatformBdsShowProgress (
    931             Foreground,
    932             Background,
    933             TmpStr,
    934             Color,
    935             ((TimeoutDefault - TimeoutRemain) * 100 / TimeoutDefault),
    936             0
    937             );
    938         }
    939       }
    940     }
    941 
    942     if (TmpStr != NULL) {
    943       gBS->FreePool (TmpStr);
    944     }
    945 
    946     //
    947     // Timeout expired
    948     //
    949     if (TimeoutRemain == 0) {
    950       return EFI_TIMEOUT;
    951     }
    952   }
    953 
    954   //
    955   // User pressed some key
    956   //
    957   if (!PcdGetBool (PcdConInConnectOnDemand)) {
    958     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
    959     if (EFI_ERROR (Status)) {
    960       return Status;
    961     }
    962 
    963     if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
    964       //
    965       // User pressed enter, equivalent to select "continue"
    966       //
    967       return EFI_TIMEOUT;
    968     }
    969   }
    970 
    971   return EFI_SUCCESS;
    972 }
    973 
    974 /**
    975   This function is the main entry of the platform setup entry.
    976   The function will present the main menu of the system setup,
    977   this is the platform reference part and can be customize.
    978 
    979 
    980   @param TimeoutDefault     The fault time out value before the system
    981                             continue to boot.
    982   @param ConnectAllHappened The indicater to check if the connect all have
    983                             already happened.
    984 
    985 **/
    986 VOID
    987 PlatformBdsEnterFrontPage (
    988   IN UINT16                       TimeoutDefault,
    989   IN BOOLEAN                      ConnectAllHappened
    990   )
    991 {
    992   EFI_STATUS                         Status;
    993   EFI_STATUS                         StatusHotkey;
    994   EFI_BOOT_LOGO_PROTOCOL             *BootLogo;
    995   EFI_GRAPHICS_OUTPUT_PROTOCOL       *GraphicsOutput;
    996   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *SimpleTextOut;
    997   UINTN                              BootTextColumn;
    998   UINTN                              BootTextRow;
    999   UINT64                             OsIndication;
   1000   UINTN                              DataSize;
   1001   EFI_INPUT_KEY                      Key;
   1002 
   1003   GraphicsOutput = NULL;
   1004   SimpleTextOut = NULL;
   1005 
   1006   PERF_START (NULL, "BdsTimeOut", "BDS", 0);
   1007   //
   1008   // Indicate if we need connect all in the platform setup
   1009   //
   1010   if (ConnectAllHappened) {
   1011     gConnectAllHappened = TRUE;
   1012   }
   1013 
   1014   if (!mModeInitialized) {
   1015     //
   1016     // After the console is ready, get current video resolution
   1017     // and text mode before launching setup at first time.
   1018     //
   1019     Status = gBS->HandleProtocol (
   1020                     gST->ConsoleOutHandle,
   1021                     &gEfiGraphicsOutputProtocolGuid,
   1022                     (VOID**)&GraphicsOutput
   1023                     );
   1024     if (EFI_ERROR (Status)) {
   1025       GraphicsOutput = NULL;
   1026     }
   1027 
   1028     Status = gBS->HandleProtocol (
   1029                     gST->ConsoleOutHandle,
   1030                     &gEfiSimpleTextOutProtocolGuid,
   1031                     (VOID**)&SimpleTextOut
   1032                     );
   1033     if (EFI_ERROR (Status)) {
   1034       SimpleTextOut = NULL;
   1035     }
   1036 
   1037     if (GraphicsOutput != NULL) {
   1038       //
   1039       // Get current video resolution and text mode.
   1040       //
   1041       mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
   1042       mBootVerticalResolution   = GraphicsOutput->Mode->Info->VerticalResolution;
   1043     }
   1044 
   1045     if (SimpleTextOut != NULL) {
   1046       Status = SimpleTextOut->QueryMode (
   1047                                 SimpleTextOut,
   1048                                 SimpleTextOut->Mode->Mode,
   1049                                 &BootTextColumn,
   1050                                 &BootTextRow
   1051                                 );
   1052       mBootTextModeColumn = (UINT32)BootTextColumn;
   1053       mBootTextModeRow    = (UINT32)BootTextRow;
   1054     }
   1055 
   1056     //
   1057     // Get user defined text mode for setup.
   1058     //
   1059     mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
   1060     mSetupVerticalResolution   = PcdGet32 (PcdSetupVideoVerticalResolution);
   1061     mSetupTextModeColumn       = PcdGet32 (PcdSetupConOutColumn);
   1062     mSetupTextModeRow          = PcdGet32 (PcdSetupConOutRow);
   1063 
   1064     mModeInitialized           = TRUE;
   1065   }
   1066 
   1067 
   1068   //
   1069   // goto FrontPage directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set
   1070   //
   1071   OsIndication = 0;
   1072   DataSize = sizeof(UINT64);
   1073   Status = gRT->GetVariable (
   1074                   L"OsIndications",
   1075                   &gEfiGlobalVariableGuid,
   1076                   NULL,
   1077                   &DataSize,
   1078                   &OsIndication
   1079                   );
   1080 
   1081   //
   1082   // goto FrontPage directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
   1083   //
   1084   if (!EFI_ERROR(Status) && ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0)) {
   1085     //
   1086     // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
   1087     //
   1088     OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
   1089     Status = gRT->SetVariable (
   1090                     L"OsIndications",
   1091                     &gEfiGlobalVariableGuid,
   1092                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
   1093                     sizeof(UINT64),
   1094                     &OsIndication
   1095                     );
   1096     //
   1097     // Changing the content without increasing its size with current variable implementation shouldn't fail.
   1098     //
   1099     ASSERT_EFI_ERROR (Status);
   1100 
   1101     //
   1102     // Follow generic rule, Call ReadKeyStroke to connect ConIn before enter UI
   1103     //
   1104     if (PcdGetBool (PcdConInConnectOnDemand)) {
   1105       gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
   1106     }
   1107 
   1108     //
   1109     // Ensure screen is clear when switch Console from Graphics mode to Text mode
   1110     //
   1111     gST->ConOut->EnableCursor (gST->ConOut, TRUE);
   1112     gST->ConOut->ClearScreen (gST->ConOut);
   1113 
   1114   } else {
   1115 
   1116     HotkeyBoot ();
   1117     if (TimeoutDefault != 0xffff) {
   1118       Status = ShowProgress (TimeoutDefault);
   1119       StatusHotkey = HotkeyBoot ();
   1120 
   1121       if (!FeaturePcdGet(PcdBootlogoOnlyEnable) || !EFI_ERROR(Status) || !EFI_ERROR(StatusHotkey)){
   1122         //
   1123         // Ensure screen is clear when switch Console from Graphics mode to Text mode
   1124         // Skip it in normal boot
   1125         //
   1126         gST->ConOut->EnableCursor (gST->ConOut, TRUE);
   1127         gST->ConOut->ClearScreen (gST->ConOut);
   1128       }
   1129 
   1130       if (EFI_ERROR (Status)) {
   1131         //
   1132         // Timeout or user press enter to continue
   1133         //
   1134         goto Exit;
   1135       }
   1136     }
   1137   }
   1138 
   1139   //
   1140   // Boot Logo is corrupted, report it using Boot Logo protocol.
   1141   //
   1142   Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
   1143   if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
   1144     BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
   1145   }
   1146 
   1147   //
   1148   // Install BM HiiPackages.
   1149   // Keep BootMaint HiiPackage, so that it can be covered by global setting.
   1150   //
   1151   InitBMPackage ();
   1152 
   1153   Status = EFI_SUCCESS;
   1154   do {
   1155     //
   1156     // Set proper video resolution and text mode for setup
   1157     //
   1158     BdsSetConsoleMode (TRUE);
   1159 
   1160     InitializeFrontPage (FALSE);
   1161 
   1162     //
   1163     // Update Front Page strings
   1164     //
   1165     UpdateFrontPageStrings ();
   1166 
   1167     gCallbackKey = 0;
   1168     CallFrontPage ();
   1169 
   1170     //
   1171     // If gCallbackKey is greater than 1 and less or equal to 5,
   1172     // it will launch configuration utilities.
   1173     // 2 = set language
   1174     // 3 = boot manager
   1175     // 4 = device manager
   1176     // 5 = boot maintenance manager
   1177     //
   1178     if (gCallbackKey != 0) {
   1179       REPORT_STATUS_CODE (
   1180         EFI_PROGRESS_CODE,
   1181         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP)
   1182         );
   1183     }
   1184     //
   1185     // Based on the key that was set, we can determine what to do
   1186     //
   1187     switch (gCallbackKey) {
   1188     //
   1189     // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can
   1190     // describe to their customers in documentation how to find their setup information (namely
   1191     // under the device manager and specific buckets)
   1192     //
   1193     // These entries consist of the Continue, Select language, Boot Manager, and Device Manager
   1194     //
   1195     case FRONT_PAGE_KEY_CONTINUE:
   1196       //
   1197       // User hit continue
   1198       //
   1199       break;
   1200 
   1201     case FRONT_PAGE_KEY_LANGUAGE:
   1202       //
   1203       // User made a language setting change - display front page again
   1204       //
   1205       break;
   1206 
   1207     case FRONT_PAGE_KEY_BOOT_MANAGER:
   1208       //
   1209       // Remove the installed BootMaint HiiPackages when exit.
   1210       //
   1211       FreeBMPackage ();
   1212 
   1213       //
   1214       // User chose to run the Boot Manager
   1215       //
   1216       CallBootManager ();
   1217 
   1218       //
   1219       // Reinstall BootMaint HiiPackages after exiting from Boot Manager.
   1220       //
   1221       InitBMPackage ();
   1222       break;
   1223 
   1224     case FRONT_PAGE_KEY_DEVICE_MANAGER:
   1225       //
   1226       // Display the Device Manager
   1227       //
   1228       do {
   1229         CallDeviceManager ();
   1230       } while (gCallbackKey == FRONT_PAGE_KEY_DEVICE_MANAGER);
   1231       break;
   1232 
   1233     case FRONT_PAGE_KEY_BOOT_MAINTAIN:
   1234       //
   1235       // Display the Boot Maintenance Manager
   1236       //
   1237       BdsStartBootMaint ();
   1238       break;
   1239     }
   1240 
   1241   } while ((Status == EFI_SUCCESS) && (gCallbackKey != FRONT_PAGE_KEY_CONTINUE));
   1242 
   1243   if (mLanguageString != NULL) {
   1244     FreePool (mLanguageString);
   1245     mLanguageString = NULL;
   1246   }
   1247   //
   1248   //Will leave browser, check any reset required change is applied? if yes, reset system
   1249   //
   1250   SetupResetReminder ();
   1251 
   1252   //
   1253   // Remove the installed BootMaint HiiPackages when exit.
   1254   //
   1255   FreeBMPackage ();
   1256 
   1257 Exit:
   1258   //
   1259   // Automatically load current entry
   1260   // Note: The following lines of code only execute when Auto boot
   1261   // takes affect
   1262   //
   1263   PERF_END (NULL, "BdsTimeOut", "BDS", 0);
   1264 }
   1265 
   1266 /**
   1267   This function will change video resolution and text mode
   1268   according to defined setup mode or defined boot mode
   1269 
   1270   @param  IsSetupMode   Indicate mode is changed to setup mode or boot mode.
   1271 
   1272   @retval  EFI_SUCCESS  Mode is changed successfully.
   1273   @retval  Others             Mode failed to be changed.
   1274 
   1275 **/
   1276 EFI_STATUS
   1277 EFIAPI
   1278 BdsSetConsoleMode (
   1279   BOOLEAN  IsSetupMode
   1280   )
   1281 {
   1282   EFI_GRAPHICS_OUTPUT_PROTOCOL          *GraphicsOutput;
   1283   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL       *SimpleTextOut;
   1284   UINTN                                 SizeOfInfo;
   1285   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
   1286   UINT32                                MaxGopMode;
   1287   UINT32                                MaxTextMode;
   1288   UINT32                                ModeNumber;
   1289   UINT32                                NewHorizontalResolution;
   1290   UINT32                                NewVerticalResolution;
   1291   UINT32                                NewColumns;
   1292   UINT32                                NewRows;
   1293   UINTN                                 HandleCount;
   1294   EFI_HANDLE                            *HandleBuffer;
   1295   EFI_STATUS                            Status;
   1296   UINTN                                 Index;
   1297   UINTN                                 CurrentColumn;
   1298   UINTN                                 CurrentRow;
   1299 
   1300   MaxGopMode  = 0;
   1301   MaxTextMode = 0;
   1302 
   1303   //
   1304   // Get current video resolution and text mode
   1305   //
   1306   Status = gBS->HandleProtocol (
   1307                   gST->ConsoleOutHandle,
   1308                   &gEfiGraphicsOutputProtocolGuid,
   1309                   (VOID**)&GraphicsOutput
   1310                   );
   1311   if (EFI_ERROR (Status)) {
   1312     GraphicsOutput = NULL;
   1313   }
   1314 
   1315   Status = gBS->HandleProtocol (
   1316                   gST->ConsoleOutHandle,
   1317                   &gEfiSimpleTextOutProtocolGuid,
   1318                   (VOID**)&SimpleTextOut
   1319                   );
   1320   if (EFI_ERROR (Status)) {
   1321     SimpleTextOut = NULL;
   1322   }
   1323 
   1324   if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
   1325     return EFI_UNSUPPORTED;
   1326   }
   1327 
   1328   if (IsSetupMode) {
   1329     //
   1330     // The required resolution and text mode is setup mode.
   1331     //
   1332     NewHorizontalResolution = mSetupHorizontalResolution;
   1333     NewVerticalResolution   = mSetupVerticalResolution;
   1334     NewColumns              = mSetupTextModeColumn;
   1335     NewRows                 = mSetupTextModeRow;
   1336   } else {
   1337     //
   1338     // The required resolution and text mode is boot mode.
   1339     //
   1340     NewHorizontalResolution = mBootHorizontalResolution;
   1341     NewVerticalResolution   = mBootVerticalResolution;
   1342     NewColumns              = mBootTextModeColumn;
   1343     NewRows                 = mBootTextModeRow;
   1344   }
   1345 
   1346   if (GraphicsOutput != NULL) {
   1347     MaxGopMode  = GraphicsOutput->Mode->MaxMode;
   1348   }
   1349 
   1350   if (SimpleTextOut != NULL) {
   1351     MaxTextMode = SimpleTextOut->Mode->MaxMode;
   1352   }
   1353 
   1354   //
   1355   // 1. If current video resolution is same with required video resolution,
   1356   //    video resolution need not be changed.
   1357   //    1.1. If current text mode is same with required text mode, text mode need not be changed.
   1358   //    1.2. If current text mode is different from required text mode, text mode need be changed.
   1359   // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.
   1360   //
   1361   for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
   1362     Status = GraphicsOutput->QueryMode (
   1363                        GraphicsOutput,
   1364                        ModeNumber,
   1365                        &SizeOfInfo,
   1366                        &Info
   1367                        );
   1368     if (!EFI_ERROR (Status)) {
   1369       if ((Info->HorizontalResolution == NewHorizontalResolution) &&
   1370           (Info->VerticalResolution == NewVerticalResolution)) {
   1371         if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&
   1372             (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {
   1373           //
   1374           // Current resolution is same with required resolution, check if text mode need be set
   1375           //
   1376           Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
   1377           ASSERT_EFI_ERROR (Status);
   1378           if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
   1379             //
   1380             // If current text mode is same with required text mode. Do nothing
   1381             //
   1382             FreePool (Info);
   1383             return EFI_SUCCESS;
   1384           } else {
   1385             //
   1386             // If current text mode is different from required text mode.  Set new video mode
   1387             //
   1388             for (Index = 0; Index < MaxTextMode; Index++) {
   1389               Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
   1390               if (!EFI_ERROR(Status)) {
   1391                 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
   1392                   //
   1393                   // Required text mode is supported, set it.
   1394                   //
   1395                   Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
   1396                   ASSERT_EFI_ERROR (Status);
   1397                   //
   1398                   // Update text mode PCD.
   1399                   //
   1400                   Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn);
   1401                   ASSERT_EFI_ERROR (Status);
   1402                   Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow);
   1403                   ASSERT_EFI_ERROR (Status);
   1404                   FreePool (Info);
   1405                   return EFI_SUCCESS;
   1406                 }
   1407               }
   1408             }
   1409             if (Index == MaxTextMode) {
   1410               //
   1411               // If required text mode is not supported, return error.
   1412               //
   1413               FreePool (Info);
   1414               return EFI_UNSUPPORTED;
   1415             }
   1416           }
   1417         } else {
   1418           //
   1419           // If current video resolution is not same with the new one, set new video resolution.
   1420           // In this case, the driver which produces simple text out need be restarted.
   1421           //
   1422           Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
   1423           if (!EFI_ERROR (Status)) {
   1424             FreePool (Info);
   1425             break;
   1426           }
   1427         }
   1428       }
   1429       FreePool (Info);
   1430     }
   1431   }
   1432 
   1433   if (ModeNumber == MaxGopMode) {
   1434     //
   1435     // If the resolution is not supported, return error.
   1436     //
   1437     return EFI_UNSUPPORTED;
   1438   }
   1439 
   1440   //
   1441   // Set PCD to Inform GraphicsConsole to change video resolution.
   1442   // Set PCD to Inform Consplitter to change text mode.
   1443   //
   1444   Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);
   1445   ASSERT_EFI_ERROR (Status);
   1446   Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);
   1447   ASSERT_EFI_ERROR (Status);
   1448   Status = PcdSet32S (PcdConOutColumn, NewColumns);
   1449   ASSERT_EFI_ERROR (Status);
   1450   Status = PcdSet32S (PcdConOutRow, NewRows);
   1451   ASSERT_EFI_ERROR (Status);
   1452 
   1453 
   1454   //
   1455   // Video mode is changed, so restart graphics console driver and higher level driver.
   1456   // Reconnect graphics console driver and higher level driver.
   1457   // Locate all the handles with GOP protocol and reconnect it.
   1458   //
   1459   Status = gBS->LocateHandleBuffer (
   1460                    ByProtocol,
   1461                    &gEfiSimpleTextOutProtocolGuid,
   1462                    NULL,
   1463                    &HandleCount,
   1464                    &HandleBuffer
   1465                    );
   1466   if (!EFI_ERROR (Status)) {
   1467     for (Index = 0; Index < HandleCount; Index++) {
   1468       gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
   1469     }
   1470     for (Index = 0; Index < HandleCount; Index++) {
   1471       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
   1472     }
   1473     if (HandleBuffer != NULL) {
   1474       FreePool (HandleBuffer);
   1475     }
   1476   }
   1477 
   1478   return EFI_SUCCESS;
   1479 }
   1480 
   1481