1 /** @file
2   FrontPage routines to handle the callbacks and browser calls
3 
4 Copyright (c) 2004 - 2014, 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   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   CurrentLang = GetEfiGlobalVariable (L"PlatformLang");
399 
400   //
401   // Get Support language list from variable.
402   //
403   if (mLanguageString == NULL){
404     mLanguageString = GetEfiGlobalVariable (L"PlatformLangCodes");
405     if (mLanguageString == NULL) {
406       mLanguageString = AllocateCopyPool (
407                                  AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),
408                                  (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)
409                                  );
410       ASSERT (mLanguageString != NULL);
411     }
412   }
413 
414   if (gFrontPagePrivate.LanguageToken == NULL) {
415     //
416     // Count the language list number.
417     //
418     LangCode      = mLanguageString;
419     Lang          = AllocatePool (AsciiStrSize (mLanguageString));
420     ASSERT (Lang != NULL);
421     OptionCount = 0;
422     while (*LangCode != 0) {
423       GetNextLanguage (&LangCode, Lang);
424       OptionCount ++;
425     }
426 
427     //
428     // Allocate extra 1 as the end tag.
429     //
430     gFrontPagePrivate.LanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID));
431     ASSERT (gFrontPagePrivate.LanguageToken != NULL);
432 
433     Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
434     ASSERT_EFI_ERROR (Status);
435 
436     LangCode     = mLanguageString;
437     OptionCount  = 0;
438     while (*LangCode != 0) {
439       GetNextLanguage (&LangCode, Lang);
440 
441       StringSize = 0;
442       Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
443       if (Status == EFI_BUFFER_TOO_SMALL) {
444         StringBuffer = AllocateZeroPool (StringSize);
445         ASSERT (StringBuffer != NULL);
446         Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
447         ASSERT_EFI_ERROR (Status);
448       }
449 
450       if (EFI_ERROR (Status)) {
451         StringBuffer = AllocatePool (AsciiStrSize (Lang) * sizeof (CHAR16));
452         ASSERT (StringBuffer != NULL);
453         AsciiStrToUnicodeStr (Lang, StringBuffer);
454       }
455 
456       ASSERT (StringBuffer != NULL);
457       gFrontPagePrivate.LanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);
458       FreePool (StringBuffer);
459 
460       OptionCount++;
461     }
462   }
463 
464   ASSERT (gFrontPagePrivate.LanguageToken != NULL);
465   LangCode     = mLanguageString;
466   OptionCount  = 0;
467   if (Lang == NULL) {
468     Lang = AllocatePool (AsciiStrSize (mLanguageString));
469     ASSERT (Lang != NULL);
470   }
471   while (*LangCode != 0) {
472     GetNextLanguage (&LangCode, Lang);
473 
474     if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) {
475       HiiCreateOneOfOptionOpCode (
476         OptionsOpCodeHandle,
477         gFrontPagePrivate.LanguageToken[OptionCount],
478         EFI_IFR_OPTION_DEFAULT,
479         EFI_IFR_NUMERIC_SIZE_1,
480         (UINT8) OptionCount
481         );
482     } else {
483       HiiCreateOneOfOptionOpCode (
484         OptionsOpCodeHandle,
485         gFrontPagePrivate.LanguageToken[OptionCount],
486         0,
487         EFI_IFR_NUMERIC_SIZE_1,
488         (UINT8) OptionCount
489         );
490     }
491 
492     OptionCount++;
493   }
494 
495   if (CurrentLang != NULL) {
496     FreePool (CurrentLang);
497   }
498   FreePool (Lang);
499 
500   HiiCreateOneOfOpCode (
501     StartOpCodeHandle,
502     FRONT_PAGE_KEY_LANGUAGE,
503     0,
504     0,
505     STRING_TOKEN (STR_LANGUAGE_SELECT),
506     STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),
507     EFI_IFR_FLAG_CALLBACK,
508     EFI_IFR_NUMERIC_SIZE_1,
509     OptionsOpCodeHandle,
510     NULL
511     );
512 
513   Status = HiiUpdateForm (
514              HiiHandle,
515              &gFrontPageFormSetGuid,
516              FRONT_PAGE_FORM_ID,
517              StartOpCodeHandle, // LABEL_SELECT_LANGUAGE
518              EndOpCodeHandle    // LABEL_END
519              );
520 
521   HiiFreeOpCodeHandle (StartOpCodeHandle);
522   HiiFreeOpCodeHandle (EndOpCodeHandle);
523   HiiFreeOpCodeHandle (OptionsOpCodeHandle);
524   return Status;
525 }
526 
527 /**
528   Call the browser and display the front page
529 
530   @return   Status code that will be returned by
531             EFI_FORM_BROWSER2_PROTOCOL.SendForm ().
532 
533 **/
534 EFI_STATUS
CallFrontPage(VOID)535 CallFrontPage (
536   VOID
537   )
538 {
539   EFI_STATUS                  Status;
540   EFI_BROWSER_ACTION_REQUEST  ActionRequest;
541 
542   //
543   // Begin waiting for USER INPUT
544   //
545   REPORT_STATUS_CODE (
546     EFI_PROGRESS_CODE,
547     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_INPUT_WAIT)
548     );
549 
550   ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
551   Status = gFormBrowser2->SendForm (
552                             gFormBrowser2,
553                             &gFrontPagePrivate.HiiHandle,
554                             1,
555                             &gFrontPageFormSetGuid,
556                             0,
557                             NULL,
558                             &ActionRequest
559                             );
560   //
561   // Check whether user change any option setting which needs a reset to be effective
562   //
563   if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
564     EnableResetRequired ();
565   }
566 
567   return Status;
568 }
569 
570 /**
571   Acquire the string associated with the ProducerGuid and return it.
572 
573 
574   @param ProducerGuid    The Guid to search the HII database for
575   @param Token           The token value of the string to extract
576   @param String          The string that is extracted
577 
578   @retval  EFI_SUCCESS  The function returns EFI_SUCCESS always.
579 
580 **/
581 EFI_STATUS
GetProducerString(IN EFI_GUID * ProducerGuid,IN EFI_STRING_ID Token,OUT CHAR16 ** String)582 GetProducerString (
583   IN      EFI_GUID                  *ProducerGuid,
584   IN      EFI_STRING_ID             Token,
585   OUT     CHAR16                    **String
586   )
587 {
588   EFI_STRING      TmpString;
589 
590   TmpString = HiiGetPackageString (ProducerGuid, Token, NULL);
591   if (TmpString == NULL) {
592     *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));
593   } else {
594     *String = TmpString;
595   }
596 
597   return EFI_SUCCESS;
598 }
599 
600 /**
601   Convert Processor Frequency Data to a string.
602 
603   @param ProcessorFrequency The frequency data to process
604   @param Base10Exponent     The exponent based on 10
605   @param String             The string that is created
606 
607 **/
608 VOID
ConvertProcessorToString(IN UINT16 ProcessorFrequency,IN UINT16 Base10Exponent,OUT CHAR16 ** String)609 ConvertProcessorToString (
610   IN  UINT16                               ProcessorFrequency,
611   IN  UINT16                               Base10Exponent,
612   OUT CHAR16                               **String
613   )
614 {
615   CHAR16  *StringBuffer;
616   UINTN   Index;
617   UINT32  FreqMhz;
618 
619   if (Base10Exponent >= 6) {
620     FreqMhz = ProcessorFrequency;
621     for (Index = 0; Index < (UINTN) (Base10Exponent - 6); Index++) {
622       FreqMhz *= 10;
623     }
624   } else {
625     FreqMhz = 0;
626   }
627 
628   StringBuffer = AllocateZeroPool (0x20);
629   ASSERT (StringBuffer != NULL);
630   Index = UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, FreqMhz / 1000, 3);
631   StrCat (StringBuffer, L".");
632   UnicodeValueToString (StringBuffer + Index + 1, PREFIX_ZERO, (FreqMhz % 1000) / 10, 2);
633   StrCat (StringBuffer, L" GHz");
634   *String = (CHAR16 *) StringBuffer;
635   return ;
636 }
637 
638 
639 /**
640   Convert Memory Size to a string.
641 
642   @param MemorySize      The size of the memory to process
643   @param String          The string that is created
644 
645 **/
646 VOID
ConvertMemorySizeToString(IN UINT32 MemorySize,OUT CHAR16 ** String)647 ConvertMemorySizeToString (
648   IN  UINT32          MemorySize,
649   OUT CHAR16          **String
650   )
651 {
652   CHAR16  *StringBuffer;
653 
654   StringBuffer = AllocateZeroPool (0x20);
655   ASSERT (StringBuffer != NULL);
656   UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, MemorySize, 6);
657   StrCat (StringBuffer, L" MB RAM");
658 
659   *String = (CHAR16 *) StringBuffer;
660 
661   return ;
662 }
663 
664 /**
665 
666   Acquire the string associated with the Index from smbios structure and return it.
667   The caller is responsible for free the string buffer.
668 
669   @param    OptionalStrStart  The start position to search the string
670   @param    Index             The index of the string to extract
671   @param    String            The string that is extracted
672 
673   @retval   EFI_SUCCESS       The function returns EFI_SUCCESS always.
674 
675 **/
676 EFI_STATUS
GetOptionalStringByIndex(IN CHAR8 * OptionalStrStart,IN UINT8 Index,OUT CHAR16 ** String)677 GetOptionalStringByIndex (
678   IN      CHAR8                   *OptionalStrStart,
679   IN      UINT8                   Index,
680   OUT     CHAR16                  **String
681   )
682 {
683   UINTN          StrSize;
684 
685   if (Index == 0) {
686     *String = AllocateZeroPool (sizeof (CHAR16));
687     return EFI_SUCCESS;
688   }
689 
690   StrSize = 0;
691   do {
692     Index--;
693     OptionalStrStart += StrSize;
694     StrSize           = AsciiStrSize (OptionalStrStart);
695   } while (OptionalStrStart[StrSize] != 0 && Index != 0);
696 
697   if ((Index != 0) || (StrSize == 1)) {
698     //
699     // Meet the end of strings set but Index is non-zero, or
700     // Find an empty string
701     //
702     *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));
703   } else {
704     *String = AllocatePool (StrSize * sizeof (CHAR16));
705     AsciiStrToUnicodeStr (OptionalStrStart, *String);
706   }
707 
708   return EFI_SUCCESS;
709 }
710 
711 
712 /**
713   Update the banner information for the Front Page based on DataHub information.
714 
715 **/
716 VOID
UpdateFrontPageStrings(VOID)717 UpdateFrontPageStrings (
718   VOID
719   )
720 {
721   UINT8                             StrIndex;
722   CHAR16                            *NewString;
723   BOOLEAN                           Find[5];
724   EFI_STATUS                        Status;
725   EFI_STRING_ID                     TokenToUpdate;
726   EFI_SMBIOS_HANDLE                 SmbiosHandle;
727   EFI_SMBIOS_PROTOCOL               *Smbios;
728   SMBIOS_TABLE_TYPE0                *Type0Record;
729   SMBIOS_TABLE_TYPE1                *Type1Record;
730   SMBIOS_TABLE_TYPE4                *Type4Record;
731   SMBIOS_TABLE_TYPE19               *Type19Record;
732   EFI_SMBIOS_TABLE_HEADER           *Record;
733 
734   ZeroMem (Find, sizeof (Find));
735 
736   //
737   // Update Front Page strings
738   //
739   Status = gBS->LocateProtocol (
740                   &gEfiSmbiosProtocolGuid,
741                   NULL,
742                   (VOID **) &Smbios
743                   );
744   ASSERT_EFI_ERROR (Status);
745 
746   SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
747   do {
748     Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
749     if (EFI_ERROR(Status)) {
750       break;
751     }
752 
753     if (Record->Type == EFI_SMBIOS_TYPE_BIOS_INFORMATION) {
754       Type0Record = (SMBIOS_TABLE_TYPE0 *) Record;
755       StrIndex = Type0Record->BiosVersion;
756       GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type0Record + Type0Record->Hdr.Length), StrIndex, &NewString);
757       TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION);
758       HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
759       FreePool (NewString);
760       Find[0] = TRUE;
761     }
762 
763     if (Record->Type == EFI_SMBIOS_TYPE_SYSTEM_INFORMATION) {
764       Type1Record = (SMBIOS_TABLE_TYPE1 *) Record;
765       StrIndex = Type1Record->ProductName;
766       GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);
767       TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL);
768       HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
769       FreePool (NewString);
770       Find[1] = TRUE;
771     }
772 
773     if (Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) {
774       Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
775       StrIndex = Type4Record->ProcessorVersion;
776       GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString);
777       TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL);
778       HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
779       FreePool (NewString);
780       Find[2] = TRUE;
781     }
782 
783     if (Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) {
784       Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
785       ConvertProcessorToString(Type4Record->CurrentSpeed, 6, &NewString);
786       TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED);
787       HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
788       FreePool (NewString);
789       Find[3] = TRUE;
790     }
791 
792     if ( Record->Type == EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS ) {
793       Type19Record = (SMBIOS_TABLE_TYPE19 *) Record;
794       ConvertMemorySizeToString (
795         (UINT32)(RShiftU64((Type19Record->EndingAddress - Type19Record->StartingAddress + 1), 10)),
796         &NewString
797         );
798       TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE);
799       HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
800       FreePool (NewString);
801       Find[4] = TRUE;
802     }
803   } while ( !(Find[0] && Find[1] && Find[2] && Find[3] && Find[4]));
804   return ;
805 }
806 
807 
808 /**
809   Function waits for a given event to fire, or for an optional timeout to expire.
810 
811   @param   Event              The event to wait for
812   @param   Timeout            An optional timeout value in 100 ns units.
813 
814   @retval  EFI_SUCCESS      Event fired before Timeout expired.
815   @retval  EFI_TIME_OUT     Timout expired before Event fired..
816 
817 **/
818 EFI_STATUS
WaitForSingleEvent(IN EFI_EVENT Event,IN UINT64 Timeout OPTIONAL)819 WaitForSingleEvent (
820   IN EFI_EVENT                  Event,
821   IN UINT64                     Timeout OPTIONAL
822   )
823 {
824   UINTN       Index;
825   EFI_STATUS  Status;
826   EFI_EVENT   TimerEvent;
827   EFI_EVENT   WaitList[2];
828 
829   if (Timeout != 0) {
830     //
831     // Create a timer event
832     //
833     Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
834     if (!EFI_ERROR (Status)) {
835       //
836       // Set the timer event
837       //
838       gBS->SetTimer (
839              TimerEvent,
840              TimerRelative,
841              Timeout
842              );
843 
844       //
845       // Wait for the original event or the timer
846       //
847       WaitList[0] = Event;
848       WaitList[1] = TimerEvent;
849       Status      = gBS->WaitForEvent (2, WaitList, &Index);
850       gBS->CloseEvent (TimerEvent);
851 
852       //
853       // If the timer expired, change the return to timed out
854       //
855       if (!EFI_ERROR (Status) && Index == 1) {
856         Status = EFI_TIMEOUT;
857       }
858     }
859   } else {
860     //
861     // No timeout... just wait on the event
862     //
863     Status = gBS->WaitForEvent (1, &Event, &Index);
864     ASSERT (!EFI_ERROR (Status));
865     ASSERT (Index == 0);
866   }
867 
868   return Status;
869 }
870 
871 /**
872   Function show progress bar to wait for user input.
873 
874 
875   @param   TimeoutDefault  The fault time out value before the system continue to boot.
876 
877   @retval  EFI_SUCCESS       User pressed some key except "Enter"
878   @retval  EFI_TIME_OUT      Timeout expired or user press "Enter"
879 
880 **/
881 EFI_STATUS
ShowProgress(IN UINT16 TimeoutDefault)882 ShowProgress (
883   IN UINT16                       TimeoutDefault
884   )
885 {
886   CHAR16                        *TmpStr;
887   UINT16                        TimeoutRemain;
888   EFI_STATUS                    Status;
889   EFI_INPUT_KEY                 Key;
890   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
891   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
892   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
893 
894   if (TimeoutDefault == 0) {
895     return EFI_TIMEOUT;
896   }
897 
898   DEBUG ((EFI_D_INFO, "\n\nStart showing progress bar... Press any key to stop it! ...Zzz....\n"));
899 
900   SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
901   SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
902   SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
903 
904   TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION));
905 
906   if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
907     //
908     // Clear the progress status bar first
909     //
910     if (TmpStr != NULL) {
911       PlatformBdsShowProgress (Foreground, Background, TmpStr, Color, 0, 0);
912     }
913   }
914 
915 
916   TimeoutRemain = TimeoutDefault;
917   while (TimeoutRemain != 0) {
918     DEBUG ((EFI_D_INFO, "Showing progress bar...Remaining %d second!\n", TimeoutRemain));
919 
920     Status = WaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);
921     if (Status != EFI_TIMEOUT) {
922       break;
923     }
924     TimeoutRemain--;
925 
926     if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
927       //
928       // Show progress
929       //
930       if (TmpStr != NULL) {
931         PlatformBdsShowProgress (
932           Foreground,
933           Background,
934           TmpStr,
935           Color,
936           ((TimeoutDefault - TimeoutRemain) * 100 / TimeoutDefault),
937           0
938           );
939       }
940     }
941   }
942 
943   if (TmpStr != NULL) {
944     gBS->FreePool (TmpStr);
945   }
946 
947   //
948   // Timeout expired
949   //
950   if (TimeoutRemain == 0) {
951     return EFI_TIMEOUT;
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 requried 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 requried 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                   PcdSet32 (PcdConOutColumn, mSetupTextModeColumn);
1401                   PcdSet32 (PcdConOutRow, mSetupTextModeRow);
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   PcdSet32 (PcdVideoHorizontalResolution, NewHorizontalResolution);
1443   PcdSet32 (PcdVideoVerticalResolution, NewVerticalResolution);
1444   PcdSet32 (PcdConOutColumn, NewColumns);
1445   PcdSet32 (PcdConOutRow, NewRows);
1446 
1447 
1448   //
1449   // Video mode is changed, so restart graphics console driver and higher level driver.
1450   // Reconnect graphics console driver and higher level driver.
1451   // Locate all the handles with GOP protocol and reconnect it.
1452   //
1453   Status = gBS->LocateHandleBuffer (
1454                    ByProtocol,
1455                    &gEfiSimpleTextOutProtocolGuid,
1456                    NULL,
1457                    &HandleCount,
1458                    &HandleBuffer
1459                    );
1460   if (!EFI_ERROR (Status)) {
1461     for (Index = 0; Index < HandleCount; Index++) {
1462       gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
1463     }
1464     for (Index = 0; Index < HandleCount; Index++) {
1465       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
1466     }
1467     if (HandleBuffer != NULL) {
1468       FreePool (HandleBuffer);
1469     }
1470   }
1471 
1472   return EFI_SUCCESS;
1473 }
1474 
1475