1/** @file
2  FrontPage routines to handle the callbacks and browser calls
3
4Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution.  The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13**/
14
15#include "Bds.h"
16#include "FrontPage.h"
17#include "Language.h"
18#include "Hotkey.h"
19
20BOOLEAN   mModeInitialized = FALSE;
21
22BOOLEAN   gConnectAllHappened = FALSE;
23UINTN     gCallbackKey;
24CHAR8     *mLanguageString;
25
26//
27// Boot video resolution and text mode.
28//
29UINT32    mBootHorizontalResolution    = 0;
30UINT32    mBootVerticalResolution      = 0;
31UINT32    mBootTextModeColumn          = 0;
32UINT32    mBootTextModeRow             = 0;
33//
34// BIOS setup video resolution and text mode.
35//
36UINT32    mSetupTextModeColumn         = 0;
37UINT32    mSetupTextModeRow            = 0;
38UINT32    mSetupHorizontalResolution   = 0;
39UINT32    mSetupVerticalResolution     = 0;
40
41EFI_FORM_BROWSER2_PROTOCOL      *gFormBrowser2;
42
43FRONT_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
55HII_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**/
99EFI_STATUS
100EFIAPI
101FakeExtractConfig (
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**/
131EFI_STATUS
132EFIAPI
133FakeRouteConfig (
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**/
171EFI_STATUS
172EFIAPI
173FrontPageCallback (
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**/
295EFI_STATUS
296InitializeFrontPage (
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**/
534EFI_STATUS
535CallFrontPage (
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**/
581EFI_STATUS
582GetProducerString (
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**/
608VOID
609ConvertProcessorToString (
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**/
646VOID
647ConvertMemorySizeToString (
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**/
676EFI_STATUS
677GetOptionalStringByIndex (
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**/
716VOID
717UpdateFrontPageStrings (
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**/
818EFI_STATUS
819WaitForSingleEvent (
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**/
881EFI_STATUS
882ShowProgress (
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**/
984VOID
985PlatformBdsEnterFrontPage (
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
1255Exit:
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**/
1274EFI_STATUS
1275EFIAPI
1276BdsSetConsoleMode (
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