• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
FakeExtractConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Request,OUT EFI_STRING * Progress,OUT EFI_STRING * Results)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
FakeRouteConfig(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN CONST EFI_STRING Configuration,OUT EFI_STRING * Progress)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
FrontPageCallback(IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL * This,IN EFI_BROWSER_ACTION Action,IN EFI_QUESTION_ID QuestionId,IN UINT8 Type,IN EFI_IFR_TYPE_VALUE * Value,OUT EFI_BROWSER_ACTION_REQUEST * ActionRequest)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
InitializeFrontPage(IN BOOLEAN InitializeHiiData)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
CallFrontPage(VOID)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
GetProducerString(IN EFI_GUID * ProducerGuid,IN EFI_STRING_ID Token,OUT CHAR16 ** String)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
ConvertProcessorToString(IN UINT16 ProcessorFrequency,IN UINT16 Base10Exponent,OUT CHAR16 ** String)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
ConvertMemorySizeToString(IN UINT32 MemorySize,OUT CHAR16 ** String)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
GetOptionalStringByIndex(IN CHAR8 * OptionalStrStart,IN UINT8 Index,OUT CHAR16 ** String)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
UpdateFrontPageStrings(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
WaitForSingleEvent(IN EFI_EVENT Event,IN UINT64 Timeout OPTIONAL)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
ShowProgress(IN UINT16 TimeoutDefault)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
PlatformBdsEnterFrontPage(IN UINT16 TimeoutDefault,IN BOOLEAN ConnectAllHappened)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
BdsSetConsoleMode(BOOLEAN IsSetupMode)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