1 /** @file
2   FrontPage routines to handle the callbacks and browser calls
3 
4 Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution.  The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9 
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12 
13 **/
14 
15 #include "Bds.h"
16 #include "FrontPage.h"
17 #include "Language.h"
18 #include "Hotkey.h"
19 
20 BOOLEAN   mModeInitialized = FALSE;
21 
22 BOOLEAN   gConnectAllHappened = FALSE;
23 UINTN     gCallbackKey;
24 CHAR8     *mLanguageString;
25 
26 //
27 // Boot video resolution and text mode.
28 //
29 UINT32    mBootHorizontalResolution    = 0;
30 UINT32    mBootVerticalResolution      = 0;
31 UINT32    mBootTextModeColumn          = 0;
32 UINT32    mBootTextModeRow             = 0;
33 //
34 // BIOS setup video resolution and text mode.
35 //
36 UINT32    mSetupTextModeColumn         = 0;
37 UINT32    mSetupTextModeRow            = 0;
38 UINT32    mSetupHorizontalResolution   = 0;
39 UINT32    mSetupVerticalResolution     = 0;
40 
41 EFI_FORM_BROWSER2_PROTOCOL      *gFormBrowser2;
42 
43 FRONT_PAGE_CALLBACK_DATA  gFrontPagePrivate = {
44   FRONT_PAGE_CALLBACK_DATA_SIGNATURE,
45   NULL,
46   NULL,
47   NULL,
48   {
49     FakeExtractConfig,
50     FakeRouteConfig,
51     FrontPageCallback
52   }
53 };
54 
55 HII_VENDOR_DEVICE_PATH  mFrontPageHiiVendorDevicePath = {
56   {
57     {
58       HARDWARE_DEVICE_PATH,
59       HW_VENDOR_DP,
60       {
61         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
62         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
63       }
64     },
65     FRONT_PAGE_FORMSET_GUID
66   },
67   {
68     END_DEVICE_PATH_TYPE,
69     END_ENTIRE_DEVICE_PATH_SUBTYPE,
70     {
71       (UINT8) (END_DEVICE_PATH_LENGTH),
72       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
73     }
74   }
75 };
76 
77 /**
78   This function allows a caller to extract the current configuration for one
79   or more named elements from the target driver.
80 
81 
82   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
83   @param Request         A null-terminated Unicode string in <ConfigRequest> format.
84   @param Progress        On return, points to a character in the Request string.
85                          Points to the string's null terminator if request was successful.
86                          Points to the most recent '&' before the first failing name/value
87                          pair (or the beginning of the string if the failure is in the
88                          first name/value pair) if the request was not successful.
89   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which
90                          has all values filled in for the names in the Request string.
91                          String to be allocated by the called function.
92 
93   @retval  EFI_SUCCESS            The Results is filled with the requested values.
94   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.
95   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.
96   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.
97 
98 **/
99 EFI_STATUS
100 EFIAPI
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   GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL);
399 
400   //
401   // Get Support language list from variable.
402   //
403   if (mLanguageString == NULL){
404     GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&mLanguageString, NULL);
405     if (mLanguageString == NULL) {
406       mLanguageString = AllocateCopyPool (
407                                  AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),
408                                  (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)
409                                  );
410       ASSERT (mLanguageString != NULL);
411     }
412   }
413 
414   if (gFrontPagePrivate.LanguageToken == NULL) {
415     //
416     // Count the language list number.
417     //
418     LangCode      = mLanguageString;
419     Lang          = AllocatePool (AsciiStrSize (mLanguageString));
420     ASSERT (Lang != NULL);
421     OptionCount = 0;
422     while (*LangCode != 0) {
423       GetNextLanguage (&LangCode, Lang);
424       OptionCount ++;
425     }
426 
427     //
428     // Allocate extra 1 as the end tag.
429     //
430     gFrontPagePrivate.LanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID));
431     ASSERT (gFrontPagePrivate.LanguageToken != NULL);
432 
433     Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
434     ASSERT_EFI_ERROR (Status);
435 
436     LangCode     = mLanguageString;
437     OptionCount  = 0;
438     while (*LangCode != 0) {
439       GetNextLanguage (&LangCode, Lang);
440 
441       StringSize = 0;
442       Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
443       if (Status == EFI_BUFFER_TOO_SMALL) {
444         StringBuffer = AllocateZeroPool (StringSize);
445         ASSERT (StringBuffer != NULL);
446         Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
447         ASSERT_EFI_ERROR (Status);
448       }
449 
450       if (EFI_ERROR (Status)) {
451         StringBuffer = AllocatePool (AsciiStrSize (Lang) * sizeof (CHAR16));
452         ASSERT (StringBuffer != NULL);
453         AsciiStrToUnicodeStr (Lang, StringBuffer);
454       }
455 
456       ASSERT (StringBuffer != NULL);
457       gFrontPagePrivate.LanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);
458       FreePool (StringBuffer);
459 
460       OptionCount++;
461     }
462   }
463 
464   ASSERT (gFrontPagePrivate.LanguageToken != NULL);
465   LangCode     = mLanguageString;
466   OptionCount  = 0;
467   if (Lang == NULL) {
468     Lang = AllocatePool (AsciiStrSize (mLanguageString));
469     ASSERT (Lang != NULL);
470   }
471   while (*LangCode != 0) {
472     GetNextLanguage (&LangCode, Lang);
473 
474     if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) {
475       HiiCreateOneOfOptionOpCode (
476         OptionsOpCodeHandle,
477         gFrontPagePrivate.LanguageToken[OptionCount],
478         EFI_IFR_OPTION_DEFAULT,
479         EFI_IFR_NUMERIC_SIZE_1,
480         (UINT8) OptionCount
481         );
482     } else {
483       HiiCreateOneOfOptionOpCode (
484         OptionsOpCodeHandle,
485         gFrontPagePrivate.LanguageToken[OptionCount],
486         0,
487         EFI_IFR_NUMERIC_SIZE_1,
488         (UINT8) OptionCount
489         );
490     }
491 
492     OptionCount++;
493   }
494 
495   if (CurrentLang != NULL) {
496     FreePool (CurrentLang);
497   }
498   FreePool (Lang);
499 
500   HiiCreateOneOfOpCode (
501     StartOpCodeHandle,
502     FRONT_PAGE_KEY_LANGUAGE,
503     0,
504     0,
505     STRING_TOKEN (STR_LANGUAGE_SELECT),
506     STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),
507     EFI_IFR_FLAG_CALLBACK,
508     EFI_IFR_NUMERIC_SIZE_1,
509     OptionsOpCodeHandle,
510     NULL
511     );
512 
513   Status = HiiUpdateForm (
514              HiiHandle,
515              &gFrontPageFormSetGuid,
516              FRONT_PAGE_FORM_ID,
517              StartOpCodeHandle, // LABEL_SELECT_LANGUAGE
518              EndOpCodeHandle    // LABEL_END
519              );
520 
521   HiiFreeOpCodeHandle (StartOpCodeHandle);
522   HiiFreeOpCodeHandle (EndOpCodeHandle);
523   HiiFreeOpCodeHandle (OptionsOpCodeHandle);
524   return Status;
525 }
526 
527 /**
528   Call the browser and display the front page
529 
530   @return   Status code that will be returned by
531             EFI_FORM_BROWSER2_PROTOCOL.SendForm ().
532 
533 **/
534 EFI_STATUS
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   StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L".");
632   UnicodeValueToString (StringBuffer + Index + 1, PREFIX_ZERO, (FreqMhz % 1000) / 10, 2);
633   StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L" GHz");
634   *String = (CHAR16 *) StringBuffer;
635   return ;
636 }
637 
638 
639 /**
640   Convert Memory Size to a string.
641 
642   @param MemorySize      The size of the memory to process
643   @param String          The string that is created
644 
645 **/
646 VOID
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   StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L" MB RAM");
658 
659   *String = (CHAR16 *) StringBuffer;
660 
661   return ;
662 }
663 
664 /**
665 
666   Acquire the string associated with the Index from smbios structure and return it.
667   The caller is responsible for free the string buffer.
668 
669   @param    OptionalStrStart  The start position to search the string
670   @param    Index             The index of the string to extract
671   @param    String            The string that is extracted
672 
673   @retval   EFI_SUCCESS       The function returns EFI_SUCCESS always.
674 
675 **/
676 EFI_STATUS
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   if (!EFI_ERROR (Status)) {
745     SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
746     do {
747       Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
748       if (EFI_ERROR(Status)) {
749         break;
750       }
751 
752       if (Record->Type == EFI_SMBIOS_TYPE_BIOS_INFORMATION) {
753         Type0Record = (SMBIOS_TABLE_TYPE0 *) Record;
754         StrIndex = Type0Record->BiosVersion;
755         GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type0Record + Type0Record->Hdr.Length), StrIndex, &NewString);
756         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION);
757         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
758         FreePool (NewString);
759         Find[0] = TRUE;
760       }
761 
762       if (Record->Type == EFI_SMBIOS_TYPE_SYSTEM_INFORMATION) {
763         Type1Record = (SMBIOS_TABLE_TYPE1 *) Record;
764         StrIndex = Type1Record->ProductName;
765         GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);
766         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL);
767         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
768         FreePool (NewString);
769         Find[1] = TRUE;
770       }
771 
772       if (Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) {
773         Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
774         StrIndex = Type4Record->ProcessorVersion;
775         GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString);
776         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL);
777         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
778         FreePool (NewString);
779         Find[2] = TRUE;
780       }
781 
782       if (Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) {
783         Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
784         ConvertProcessorToString(Type4Record->CurrentSpeed, 6, &NewString);
785         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED);
786         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
787         FreePool (NewString);
788         Find[3] = TRUE;
789       }
790 
791       if ( Record->Type == EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS ) {
792         Type19Record = (SMBIOS_TABLE_TYPE19 *) Record;
793         ConvertMemorySizeToString (
794           (UINT32)(RShiftU64((Type19Record->EndingAddress - Type19Record->StartingAddress + 1), 10)),
795           &NewString
796           );
797         TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE);
798         HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
799         FreePool (NewString);
800         Find[4] = TRUE;
801       }
802     } while ( !(Find[0] && Find[1] && Find[2] && Find[3] && Find[4]));
803   }
804   return ;
805 }
806 
807 
808 /**
809   Function waits for a given event to fire, or for an optional timeout to expire.
810 
811   @param   Event              The event to wait for
812   @param   Timeout            An optional timeout value in 100 ns units.
813 
814   @retval  EFI_SUCCESS      Event fired before Timeout expired.
815   @retval  EFI_TIME_OUT     Timout expired before Event fired..
816 
817 **/
818 EFI_STATUS
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     DEBUG ((EFI_D_INFO, "\n\nStart showing progress bar... Press any key to stop it! ...Zzz....\n"));
896 
897     SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
898     SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
899     SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
900 
901     TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION));
902 
903     if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
904       //
905       // Clear the progress status bar first
906       //
907       if (TmpStr != NULL) {
908         PlatformBdsShowProgress (Foreground, Background, TmpStr, Color, 0, 0);
909       }
910     }
911 
912 
913     TimeoutRemain = TimeoutDefault;
914     while (TimeoutRemain != 0) {
915       DEBUG ((EFI_D_INFO, "Showing progress bar...Remaining %d second!\n", TimeoutRemain));
916 
917       Status = WaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);
918       if (Status != EFI_TIMEOUT) {
919         break;
920       }
921       TimeoutRemain--;
922 
923       if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
924         //
925         // Show progress
926         //
927         if (TmpStr != NULL) {
928           PlatformBdsShowProgress (
929             Foreground,
930             Background,
931             TmpStr,
932             Color,
933             ((TimeoutDefault - TimeoutRemain) * 100 / TimeoutDefault),
934             0
935             );
936         }
937       }
938     }
939 
940     if (TmpStr != NULL) {
941       gBS->FreePool (TmpStr);
942     }
943 
944     //
945     // Timeout expired
946     //
947     if (TimeoutRemain == 0) {
948       return EFI_TIMEOUT;
949     }
950   }
951 
952   //
953   // User pressed some key
954   //
955   if (!PcdGetBool (PcdConInConnectOnDemand)) {
956     Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
957     if (EFI_ERROR (Status)) {
958       return Status;
959     }
960 
961     if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
962       //
963       // User pressed enter, equivalent to select "continue"
964       //
965       return EFI_TIMEOUT;
966     }
967   }
968 
969   return EFI_SUCCESS;
970 }
971 
972 /**
973   This function is the main entry of the platform setup entry.
974   The function will present the main menu of the system setup,
975   this is the platform reference part and can be customize.
976 
977 
978   @param TimeoutDefault     The fault time out value before the system
979                             continue to boot.
980   @param ConnectAllHappened The indicater to check if the connect all have
981                             already happened.
982 
983 **/
984 VOID
PlatformBdsEnterFrontPage(IN UINT16 TimeoutDefault,IN BOOLEAN ConnectAllHappened)985 PlatformBdsEnterFrontPage (
986   IN UINT16                       TimeoutDefault,
987   IN BOOLEAN                      ConnectAllHappened
988   )
989 {
990   EFI_STATUS                         Status;
991   EFI_STATUS                         StatusHotkey;
992   EFI_BOOT_LOGO_PROTOCOL             *BootLogo;
993   EFI_GRAPHICS_OUTPUT_PROTOCOL       *GraphicsOutput;
994   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL    *SimpleTextOut;
995   UINTN                              BootTextColumn;
996   UINTN                              BootTextRow;
997   UINT64                             OsIndication;
998   UINTN                              DataSize;
999   EFI_INPUT_KEY                      Key;
1000 
1001   GraphicsOutput = NULL;
1002   SimpleTextOut = NULL;
1003 
1004   PERF_START (NULL, "BdsTimeOut", "BDS", 0);
1005   //
1006   // Indicate if we need connect all in the platform setup
1007   //
1008   if (ConnectAllHappened) {
1009     gConnectAllHappened = TRUE;
1010   }
1011 
1012   if (!mModeInitialized) {
1013     //
1014     // After the console is ready, get current video resolution
1015     // and text mode before launching setup at first time.
1016     //
1017     Status = gBS->HandleProtocol (
1018                     gST->ConsoleOutHandle,
1019                     &gEfiGraphicsOutputProtocolGuid,
1020                     (VOID**)&GraphicsOutput
1021                     );
1022     if (EFI_ERROR (Status)) {
1023       GraphicsOutput = NULL;
1024     }
1025 
1026     Status = gBS->HandleProtocol (
1027                     gST->ConsoleOutHandle,
1028                     &gEfiSimpleTextOutProtocolGuid,
1029                     (VOID**)&SimpleTextOut
1030                     );
1031     if (EFI_ERROR (Status)) {
1032       SimpleTextOut = NULL;
1033     }
1034 
1035     if (GraphicsOutput != NULL) {
1036       //
1037       // Get current video resolution and text mode.
1038       //
1039       mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
1040       mBootVerticalResolution   = GraphicsOutput->Mode->Info->VerticalResolution;
1041     }
1042 
1043     if (SimpleTextOut != NULL) {
1044       Status = SimpleTextOut->QueryMode (
1045                                 SimpleTextOut,
1046                                 SimpleTextOut->Mode->Mode,
1047                                 &BootTextColumn,
1048                                 &BootTextRow
1049                                 );
1050       mBootTextModeColumn = (UINT32)BootTextColumn;
1051       mBootTextModeRow    = (UINT32)BootTextRow;
1052     }
1053 
1054     //
1055     // Get user defined text mode for setup.
1056     //
1057     mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
1058     mSetupVerticalResolution   = PcdGet32 (PcdSetupVideoVerticalResolution);
1059     mSetupTextModeColumn       = PcdGet32 (PcdSetupConOutColumn);
1060     mSetupTextModeRow          = PcdGet32 (PcdSetupConOutRow);
1061 
1062     mModeInitialized           = TRUE;
1063   }
1064 
1065 
1066   //
1067   // goto FrontPage directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set
1068   //
1069   OsIndication = 0;
1070   DataSize = sizeof(UINT64);
1071   Status = gRT->GetVariable (
1072                   L"OsIndications",
1073                   &gEfiGlobalVariableGuid,
1074                   NULL,
1075                   &DataSize,
1076                   &OsIndication
1077                   );
1078 
1079   //
1080   // goto FrontPage directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
1081   //
1082   if (!EFI_ERROR(Status) && ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0)) {
1083     //
1084     // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
1085     //
1086     OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
1087     Status = gRT->SetVariable (
1088                     L"OsIndications",
1089                     &gEfiGlobalVariableGuid,
1090                     EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1091                     sizeof(UINT64),
1092                     &OsIndication
1093                     );
1094     //
1095     // Changing the content without increasing its size with current variable implementation shouldn't fail.
1096     //
1097     ASSERT_EFI_ERROR (Status);
1098 
1099     //
1100     // Follow generic rule, Call ReadKeyStroke to connect ConIn before enter UI
1101     //
1102     if (PcdGetBool (PcdConInConnectOnDemand)) {
1103       gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
1104     }
1105 
1106     //
1107     // Ensure screen is clear when switch Console from Graphics mode to Text mode
1108     //
1109     gST->ConOut->EnableCursor (gST->ConOut, TRUE);
1110     gST->ConOut->ClearScreen (gST->ConOut);
1111 
1112   } else {
1113 
1114     HotkeyBoot ();
1115     if (TimeoutDefault != 0xffff) {
1116       Status = ShowProgress (TimeoutDefault);
1117       StatusHotkey = HotkeyBoot ();
1118 
1119       if (!FeaturePcdGet(PcdBootlogoOnlyEnable) || !EFI_ERROR(Status) || !EFI_ERROR(StatusHotkey)){
1120         //
1121         // Ensure screen is clear when switch Console from Graphics mode to Text mode
1122         // Skip it in normal boot
1123         //
1124         gST->ConOut->EnableCursor (gST->ConOut, TRUE);
1125         gST->ConOut->ClearScreen (gST->ConOut);
1126       }
1127 
1128       if (EFI_ERROR (Status)) {
1129         //
1130         // Timeout or user press enter to continue
1131         //
1132         goto Exit;
1133       }
1134     }
1135   }
1136 
1137   //
1138   // Boot Logo is corrupted, report it using Boot Logo protocol.
1139   //
1140   Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
1141   if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
1142     BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
1143   }
1144 
1145   //
1146   // Install BM HiiPackages.
1147   // Keep BootMaint HiiPackage, so that it can be covered by global setting.
1148   //
1149   InitBMPackage ();
1150 
1151   Status = EFI_SUCCESS;
1152   do {
1153     //
1154     // Set proper video resolution and text mode for setup
1155     //
1156     BdsSetConsoleMode (TRUE);
1157 
1158     InitializeFrontPage (FALSE);
1159 
1160     //
1161     // Update Front Page strings
1162     //
1163     UpdateFrontPageStrings ();
1164 
1165     gCallbackKey = 0;
1166     CallFrontPage ();
1167 
1168     //
1169     // If gCallbackKey is greater than 1 and less or equal to 5,
1170     // it will launch configuration utilities.
1171     // 2 = set language
1172     // 3 = boot manager
1173     // 4 = device manager
1174     // 5 = boot maintenance manager
1175     //
1176     if (gCallbackKey != 0) {
1177       REPORT_STATUS_CODE (
1178         EFI_PROGRESS_CODE,
1179         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP)
1180         );
1181     }
1182     //
1183     // Based on the key that was set, we can determine what to do
1184     //
1185     switch (gCallbackKey) {
1186     //
1187     // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can
1188     // describe to their customers in documentation how to find their setup information (namely
1189     // under the device manager and specific buckets)
1190     //
1191     // These entries consist of the Continue, Select language, Boot Manager, and Device Manager
1192     //
1193     case FRONT_PAGE_KEY_CONTINUE:
1194       //
1195       // User hit continue
1196       //
1197       break;
1198 
1199     case FRONT_PAGE_KEY_LANGUAGE:
1200       //
1201       // User made a language setting change - display front page again
1202       //
1203       break;
1204 
1205     case FRONT_PAGE_KEY_BOOT_MANAGER:
1206       //
1207       // Remove the installed BootMaint HiiPackages when exit.
1208       //
1209       FreeBMPackage ();
1210 
1211       //
1212       // User chose to run the Boot Manager
1213       //
1214       CallBootManager ();
1215 
1216       //
1217       // Reinstall BootMaint HiiPackages after exiting from Boot Manager.
1218       //
1219       InitBMPackage ();
1220       break;
1221 
1222     case FRONT_PAGE_KEY_DEVICE_MANAGER:
1223       //
1224       // Display the Device Manager
1225       //
1226       do {
1227         CallDeviceManager ();
1228       } while (gCallbackKey == FRONT_PAGE_KEY_DEVICE_MANAGER);
1229       break;
1230 
1231     case FRONT_PAGE_KEY_BOOT_MAINTAIN:
1232       //
1233       // Display the Boot Maintenance Manager
1234       //
1235       BdsStartBootMaint ();
1236       break;
1237     }
1238 
1239   } while ((Status == EFI_SUCCESS) && (gCallbackKey != FRONT_PAGE_KEY_CONTINUE));
1240 
1241   if (mLanguageString != NULL) {
1242     FreePool (mLanguageString);
1243     mLanguageString = NULL;
1244   }
1245   //
1246   //Will leave browser, check any reset required change is applied? if yes, reset system
1247   //
1248   SetupResetReminder ();
1249 
1250   //
1251   // Remove the installed BootMaint HiiPackages when exit.
1252   //
1253   FreeBMPackage ();
1254 
1255 Exit:
1256   //
1257   // Automatically load current entry
1258   // Note: The following lines of code only execute when Auto boot
1259   // takes affect
1260   //
1261   PERF_END (NULL, "BdsTimeOut", "BDS", 0);
1262 }
1263 
1264 /**
1265   This function will change video resolution and text mode
1266   according to defined setup mode or defined boot mode
1267 
1268   @param  IsSetupMode   Indicate mode is changed to setup mode or boot mode.
1269 
1270   @retval  EFI_SUCCESS  Mode is changed successfully.
1271   @retval  Others             Mode failed to be changed.
1272 
1273 **/
1274 EFI_STATUS
1275 EFIAPI
BdsSetConsoleMode(BOOLEAN IsSetupMode)1276 BdsSetConsoleMode (
1277   BOOLEAN  IsSetupMode
1278   )
1279 {
1280   EFI_GRAPHICS_OUTPUT_PROTOCOL          *GraphicsOutput;
1281   EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL       *SimpleTextOut;
1282   UINTN                                 SizeOfInfo;
1283   EFI_GRAPHICS_OUTPUT_MODE_INFORMATION  *Info;
1284   UINT32                                MaxGopMode;
1285   UINT32                                MaxTextMode;
1286   UINT32                                ModeNumber;
1287   UINT32                                NewHorizontalResolution;
1288   UINT32                                NewVerticalResolution;
1289   UINT32                                NewColumns;
1290   UINT32                                NewRows;
1291   UINTN                                 HandleCount;
1292   EFI_HANDLE                            *HandleBuffer;
1293   EFI_STATUS                            Status;
1294   UINTN                                 Index;
1295   UINTN                                 CurrentColumn;
1296   UINTN                                 CurrentRow;
1297 
1298   MaxGopMode  = 0;
1299   MaxTextMode = 0;
1300 
1301   //
1302   // Get current video resolution and text mode
1303   //
1304   Status = gBS->HandleProtocol (
1305                   gST->ConsoleOutHandle,
1306                   &gEfiGraphicsOutputProtocolGuid,
1307                   (VOID**)&GraphicsOutput
1308                   );
1309   if (EFI_ERROR (Status)) {
1310     GraphicsOutput = NULL;
1311   }
1312 
1313   Status = gBS->HandleProtocol (
1314                   gST->ConsoleOutHandle,
1315                   &gEfiSimpleTextOutProtocolGuid,
1316                   (VOID**)&SimpleTextOut
1317                   );
1318   if (EFI_ERROR (Status)) {
1319     SimpleTextOut = NULL;
1320   }
1321 
1322   if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
1323     return EFI_UNSUPPORTED;
1324   }
1325 
1326   if (IsSetupMode) {
1327     //
1328     // The requried resolution and text mode is setup mode.
1329     //
1330     NewHorizontalResolution = mSetupHorizontalResolution;
1331     NewVerticalResolution   = mSetupVerticalResolution;
1332     NewColumns              = mSetupTextModeColumn;
1333     NewRows                 = mSetupTextModeRow;
1334   } else {
1335     //
1336     // The required resolution and text mode is boot mode.
1337     //
1338     NewHorizontalResolution = mBootHorizontalResolution;
1339     NewVerticalResolution   = mBootVerticalResolution;
1340     NewColumns              = mBootTextModeColumn;
1341     NewRows                 = mBootTextModeRow;
1342   }
1343 
1344   if (GraphicsOutput != NULL) {
1345     MaxGopMode  = GraphicsOutput->Mode->MaxMode;
1346   }
1347 
1348   if (SimpleTextOut != NULL) {
1349     MaxTextMode = SimpleTextOut->Mode->MaxMode;
1350   }
1351 
1352   //
1353   // 1. If current video resolution is same with required video resolution,
1354   //    video resolution need not be changed.
1355   //    1.1. If current text mode is same with required text mode, text mode need not be changed.
1356   //    1.2. If current text mode is different from required text mode, text mode need be changed.
1357   // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.
1358   //
1359   for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
1360     Status = GraphicsOutput->QueryMode (
1361                        GraphicsOutput,
1362                        ModeNumber,
1363                        &SizeOfInfo,
1364                        &Info
1365                        );
1366     if (!EFI_ERROR (Status)) {
1367       if ((Info->HorizontalResolution == NewHorizontalResolution) &&
1368           (Info->VerticalResolution == NewVerticalResolution)) {
1369         if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&
1370             (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {
1371           //
1372           // Current resolution is same with required resolution, check if text mode need be set
1373           //
1374           Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
1375           ASSERT_EFI_ERROR (Status);
1376           if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
1377             //
1378             // If current text mode is same with required text mode. Do nothing
1379             //
1380             FreePool (Info);
1381             return EFI_SUCCESS;
1382           } else {
1383             //
1384             // If current text mode is different from requried text mode.  Set new video mode
1385             //
1386             for (Index = 0; Index < MaxTextMode; Index++) {
1387               Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
1388               if (!EFI_ERROR(Status)) {
1389                 if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
1390                   //
1391                   // Required text mode is supported, set it.
1392                   //
1393                   Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
1394                   ASSERT_EFI_ERROR (Status);
1395                   //
1396                   // Update text mode PCD.
1397                   //
1398                   Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn);
1399                   ASSERT_EFI_ERROR (Status);
1400                   Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow);
1401                   ASSERT_EFI_ERROR (Status);
1402                   FreePool (Info);
1403                   return EFI_SUCCESS;
1404                 }
1405               }
1406             }
1407             if (Index == MaxTextMode) {
1408               //
1409               // If requried text mode is not supported, return error.
1410               //
1411               FreePool (Info);
1412               return EFI_UNSUPPORTED;
1413             }
1414           }
1415         } else {
1416           //
1417           // If current video resolution is not same with the new one, set new video resolution.
1418           // In this case, the driver which produces simple text out need be restarted.
1419           //
1420           Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
1421           if (!EFI_ERROR (Status)) {
1422             FreePool (Info);
1423             break;
1424           }
1425         }
1426       }
1427       FreePool (Info);
1428     }
1429   }
1430 
1431   if (ModeNumber == MaxGopMode) {
1432     //
1433     // If the resolution is not supported, return error.
1434     //
1435     return EFI_UNSUPPORTED;
1436   }
1437 
1438   //
1439   // Set PCD to Inform GraphicsConsole to change video resolution.
1440   // Set PCD to Inform Consplitter to change text mode.
1441   //
1442   Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);
1443   ASSERT_EFI_ERROR (Status);
1444   Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);
1445   ASSERT_EFI_ERROR (Status);
1446   Status = PcdSet32S (PcdConOutColumn, NewColumns);
1447   ASSERT_EFI_ERROR (Status);
1448   Status = PcdSet32S (PcdConOutRow, NewRows);
1449   ASSERT_EFI_ERROR (Status);
1450 
1451 
1452   //
1453   // Video mode is changed, so restart graphics console driver and higher level driver.
1454   // Reconnect graphics console driver and higher level driver.
1455   // Locate all the handles with GOP protocol and reconnect it.
1456   //
1457   Status = gBS->LocateHandleBuffer (
1458                    ByProtocol,
1459                    &gEfiSimpleTextOutProtocolGuid,
1460                    NULL,
1461                    &HandleCount,
1462                    &HandleBuffer
1463                    );
1464   if (!EFI_ERROR (Status)) {
1465     for (Index = 0; Index < HandleCount; Index++) {
1466       gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
1467     }
1468     for (Index = 0; Index < HandleCount; Index++) {
1469       gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
1470     }
1471     if (HandleBuffer != NULL) {
1472       FreePool (HandleBuffer);
1473     }
1474   }
1475 
1476   return EFI_SUCCESS;
1477 }
1478 
1479