Update HiiConfigAccess.ExtractConfig interface to support NULL request string and...
[efi/edk2/.git] / edk2 / IntelFrameworkModulePkg / Universal / BdsDxe / FrontPage.c
1 /** @file\r
2   FrontPage routines to handle the callbacks and browser calls\r
3 \r
4 Copyright (c) 2004 - 2009, Intel Corporation. <BR>\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution.  The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 **/\r
14 \r
15 #include "Bds.h"\r
16 #include "FrontPage.h"\r
17 #include "Language.h"\r
18 \r
19 EFI_GUID  mFrontPageGuid      = FRONT_PAGE_FORMSET_GUID;\r
20 \r
21 BOOLEAN   gConnectAllHappened = FALSE;\r
22 UINTN     gCallbackKey;\r
23 \r
24 EFI_FORM_BROWSER2_PROTOCOL      *gFormBrowser2;\r
25 \r
26 FRONT_PAGE_CALLBACK_DATA  gFrontPagePrivate = {\r
27   FRONT_PAGE_CALLBACK_DATA_SIGNATURE,\r
28   NULL,\r
29   NULL,\r
30   NULL,\r
31   {\r
32     FakeExtractConfig,\r
33     FakeRouteConfig,\r
34     FrontPageCallback\r
35   }\r
36 };\r
37 \r
38 HII_VENDOR_DEVICE_PATH  mFrontPageHiiVendorDevicePath = {\r
39   {\r
40     {\r
41       HARDWARE_DEVICE_PATH,\r
42       HW_VENDOR_DP,\r
43       {\r
44         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
45         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
46       }\r
47     },\r
48     //\r
49     // {8E6D99EE-7531-48f8-8745-7F6144468FF2}\r
50     //\r
51     { 0x8e6d99ee, 0x7531, 0x48f8, { 0x87, 0x45, 0x7f, 0x61, 0x44, 0x46, 0x8f, 0xf2 } }\r
52   },\r
53   {\r
54     END_DEVICE_PATH_TYPE,\r
55     END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
56     {\r
57       (UINT8) (END_DEVICE_PATH_LENGTH),\r
58       (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)\r
59     }\r
60   }\r
61 };\r
62 \r
63 /**\r
64   This function allows a caller to extract the current configuration for one\r
65   or more named elements from the target driver.\r
66 \r
67 \r
68   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
69   @param Request         A null-terminated Unicode string in <ConfigRequest> format.\r
70   @param Progress        On return, points to a character in the Request string.\r
71                          Points to the string's null terminator if request was successful.\r
72                          Points to the most recent '&' before the first failing name/value\r
73                          pair (or the beginning of the string if the failure is in the\r
74                          first name/value pair) if the request was not successful.\r
75   @param Results         A null-terminated Unicode string in <ConfigAltResp> format which\r
76                          has all values filled in for the names in the Request string.\r
77                          String to be allocated by the called function.\r
78 \r
79   @retval  EFI_SUCCESS            The Results is filled with the requested values.\r
80   @retval  EFI_OUT_OF_RESOURCES   Not enough memory to store the results.\r
81   @retval  EFI_INVALID_PARAMETER  Request is illegal syntax, or unknown name.\r
82   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.\r
83 \r
84 **/\r
85 EFI_STATUS\r
86 EFIAPI\r
87 FakeExtractConfig (\r
88   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
89   IN  CONST EFI_STRING                       Request,\r
90   OUT EFI_STRING                             *Progress,\r
91   OUT EFI_STRING                             *Results\r
92   )\r
93 {\r
94   if (Progress == NULL || Results == NULL) {\r
95     return EFI_INVALID_PARAMETER;\r
96   }\r
97   *Progress = Request;\r
98   return EFI_NOT_FOUND;\r
99 }\r
100 \r
101 /**\r
102   This function processes the results of changes in configuration.\r
103 \r
104 \r
105   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
106   @param Configuration   A null-terminated Unicode string in <ConfigResp> format.\r
107   @param Progress        A pointer to a string filled in with the offset of the most\r
108                          recent '&' before the first failing name/value pair (or the\r
109                          beginning of the string if the failure is in the first\r
110                          name/value pair) or the terminating NULL if all was successful.\r
111 \r
112   @retval  EFI_SUCCESS            The Results is processed successfully.\r
113   @retval  EFI_INVALID_PARAMETER  Configuration is NULL.\r
114   @retval  EFI_NOT_FOUND          Routing data doesn't match any storage in this driver.\r
115 \r
116 **/\r
117 EFI_STATUS\r
118 EFIAPI\r
119 FakeRouteConfig (\r
120   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
121   IN  CONST EFI_STRING                       Configuration,\r
122   OUT EFI_STRING                             *Progress\r
123   )\r
124 {\r
125   if (Configuration == NULL || Progress == NULL) {\r
126     return EFI_INVALID_PARAMETER;\r
127   }\r
128 \r
129   *Progress = Configuration;\r
130   if (!HiiIsConfigHdrMatch (Configuration, &mBootMaintGuid, mBootMaintStorageName)\r
131       && !HiiIsConfigHdrMatch (Configuration, &mFileExplorerGuid, mFileExplorerStorageName)) {\r
132     return EFI_NOT_FOUND;\r
133   }\r
134 \r
135   *Progress = Configuration + StrLen (Configuration);\r
136   return EFI_SUCCESS;\r
137 }\r
138 \r
139 /**\r
140   This function processes the results of changes in configuration.\r
141 \r
142 \r
143   @param This            Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
144   @param Action          Specifies the type of action taken by the browser.\r
145   @param QuestionId      A unique value which is sent to the original exporting driver\r
146                          so that it can identify the type of data to expect.\r
147   @param Type            The type of value for the question.\r
148   @param Value           A pointer to the data being sent to the original exporting driver.\r
149   @param ActionRequest   On return, points to the action requested by the callback function.\r
150 \r
151   @retval  EFI_SUCCESS           The callback successfully handled the action.\r
152   @retval  EFI_OUT_OF_RESOURCES  Not enough storage is available to hold the variable and its data.\r
153   @retval  EFI_DEVICE_ERROR      The variable could not be saved.\r
154   @retval  EFI_UNSUPPORTED       The specified Action is not supported by the callback.\r
155 \r
156 **/\r
157 EFI_STATUS\r
158 EFIAPI\r
159 FrontPageCallback (\r
160   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
161   IN  EFI_BROWSER_ACTION                     Action,\r
162   IN  EFI_QUESTION_ID                        QuestionId,\r
163   IN  UINT8                                  Type,\r
164   IN  EFI_IFR_TYPE_VALUE                     *Value,\r
165   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest\r
166   )\r
167 {\r
168   CHAR8                         *LanguageString;\r
169   CHAR8                         *LangCode;\r
170   CHAR8                         *Lang;\r
171   UINTN                         Index;\r
172   EFI_STATUS                    Status;\r
173   CHAR8                         *PlatformSupportedLanguages;\r
174   CHAR8                         *BestLanguage;\r
175 \r
176   if ((Value == NULL) || (ActionRequest == NULL)) {\r
177     return EFI_INVALID_PARAMETER;\r
178   }\r
179 \r
180   gCallbackKey = QuestionId;\r
181 \r
182   //\r
183   // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can\r
184   // describe to their customers in documentation how to find their setup information (namely\r
185   // under the device manager and specific buckets)\r
186   //\r
187   switch (QuestionId) {\r
188   case FRONT_PAGE_KEY_CONTINUE:\r
189     //\r
190     // This is the continue - clear the screen and return an error to get out of FrontPage loop\r
191     //\r
192     break;\r
193 \r
194   case FRONT_PAGE_KEY_LANGUAGE:\r
195     //\r
196     // Collect the languages from what our current Language support is based on our VFR\r
197     //\r
198     LanguageString = HiiGetSupportedLanguages (gFrontPagePrivate.HiiHandle);\r
199     ASSERT (LanguageString != NULL);\r
200     //\r
201     // Allocate working buffer for RFC 4646 language in supported LanguageString.\r
202     //\r
203     Lang = AllocatePool (AsciiStrSize (LanguageString));\r
204     ASSERT (Lang != NULL);\r
205 \r
206     Index = 0;\r
207     LangCode = LanguageString;\r
208     while (*LangCode != 0) {\r
209       GetNextLanguage (&LangCode, Lang);\r
210 \r
211       if (Index == Value->u8) {\r
212         break;\r
213       }\r
214 \r
215       Index++;\r
216     }\r
217 \r
218     PlatformSupportedLanguages = GetEfiGlobalVariable (L"PlatformLangCodes");\r
219     if (PlatformSupportedLanguages == NULL) {\r
220       PlatformSupportedLanguages = AllocateCopyPool (\r
221                                      AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),\r
222                                      (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)\r
223                                      );\r
224       ASSERT (PlatformSupportedLanguages != NULL);\r
225     }\r
226 \r
227     //\r
228     // Select the best language in platform supported Language.\r
229     //\r
230     BestLanguage = GetBestLanguage (\r
231                      PlatformSupportedLanguages,\r
232                      FALSE,\r
233                      Lang,\r
234                      NULL\r
235                      );\r
236     if (BestLanguage != NULL) {\r
237       Status = gRT->SetVariable (\r
238                       L"PlatformLang",\r
239                       &gEfiGlobalVariableGuid,\r
240                       EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
241                       AsciiStrSize (BestLanguage),\r
242                       Lang\r
243                       );\r
244       ASSERT_EFI_ERROR(Status);\r
245       FreePool (BestLanguage);\r
246     } else {\r
247       ASSERT (FALSE);\r
248     }\r
249 \r
250     FreePool (PlatformSupportedLanguages);\r
251     FreePool (Lang);\r
252     FreePool (LanguageString);\r
253     break;\r
254 \r
255   case FRONT_PAGE_KEY_BOOT_MANAGER:\r
256     //\r
257     // Boot Manager\r
258     //\r
259     break;\r
260 \r
261   case FRONT_PAGE_KEY_DEVICE_MANAGER:\r
262     //\r
263     // Device Manager\r
264     //\r
265     break;\r
266 \r
267   case FRONT_PAGE_KEY_BOOT_MAINTAIN:\r
268     //\r
269     // Boot Maintenance Manager\r
270     //\r
271     break;\r
272 \r
273   default:\r
274     gCallbackKey = 0;\r
275     break;\r
276   }\r
277 \r
278   *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
279 \r
280   return EFI_SUCCESS;\r
281 }\r
282 \r
283 /**\r
284   Initialize HII information for the FrontPage\r
285 \r
286 \r
287   @param InitializeHiiData    TRUE if HII elements need to be initialized.\r
288 \r
289   @retval  EFI_SUCCESS        The operation is successful.\r
290   @retval  EFI_DEVICE_ERROR   If the dynamic opcode creation failed.\r
291 \r
292 **/\r
293 EFI_STATUS\r
294 InitializeFrontPage (\r
295   IN BOOLEAN                         InitializeHiiData\r
296   )\r
297 {\r
298   EFI_STATUS                  Status;\r
299   CHAR8                       *LanguageString;\r
300   CHAR8                       *LangCode;\r
301   CHAR8                       *Lang;\r
302   CHAR8                       *CurrentLang;\r
303   CHAR8                       *BestLanguage;\r
304   UINTN                       OptionCount;\r
305   CHAR16                      *StringBuffer;\r
306   EFI_HII_HANDLE              HiiHandle;\r
307   VOID                        *OptionsOpCodeHandle;\r
308   VOID                        *StartOpCodeHandle;\r
309   VOID                        *EndOpCodeHandle;\r
310   EFI_IFR_GUID_LABEL          *StartLabel;\r
311   EFI_IFR_GUID_LABEL          *EndLabel;\r
312   BOOLEAN                     FirstFlag;\r
313   EFI_STRING_ID               Temp;\r
314 \r
315   if (InitializeHiiData) {\r
316     //\r
317     // Initialize the Device Manager\r
318     //\r
319     InitializeDeviceManager ();\r
320 \r
321     //\r
322     // Initialize the Device Manager\r
323     //\r
324     InitializeBootManager ();\r
325 \r
326     gCallbackKey  = 0;\r
327 \r
328     //\r
329     // Locate Hii relative protocols\r
330     //\r
331     Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFormBrowser2);\r
332     if (EFI_ERROR (Status)) {\r
333       return Status;\r
334     }\r
335 \r
336     //\r
337     // Install Device Path Protocol and Config Access protocol to driver handle\r
338     //\r
339     Status = gBS->InstallMultipleProtocolInterfaces (\r
340                     &gFrontPagePrivate.DriverHandle,\r
341                     &gEfiDevicePathProtocolGuid,\r
342                     &mFrontPageHiiVendorDevicePath,\r
343                     &gEfiHiiConfigAccessProtocolGuid,\r
344                     &gFrontPagePrivate.ConfigAccess,\r
345                     NULL\r
346                     );\r
347     ASSERT_EFI_ERROR (Status);\r
348 \r
349     //\r
350     // Publish our HII data\r
351     //\r
352     gFrontPagePrivate.HiiHandle = HiiAddPackages (\r
353                                     &mFrontPageGuid,\r
354                                     gFrontPagePrivate.DriverHandle,\r
355                                     FrontPageVfrBin,\r
356                                     BdsDxeStrings,\r
357                                     NULL\r
358                                     );\r
359     if (gFrontPagePrivate.HiiHandle == NULL) {\r
360       return EFI_OUT_OF_RESOURCES;\r
361     }\r
362   }\r
363 \r
364 \r
365   //\r
366   // Init OpCode Handle and Allocate space for creation of UpdateData Buffer\r
367   //\r
368   StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
369   ASSERT (StartOpCodeHandle != NULL);\r
370 \r
371   EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
372   ASSERT (EndOpCodeHandle != NULL);\r
373 \r
374   OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();\r
375   ASSERT (OptionsOpCodeHandle != NULL);\r
376   //\r
377   // Create Hii Extend Label OpCode as the start opcode\r
378   //\r
379   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
380   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
381   StartLabel->Number       = LABEL_SELECT_LANGUAGE;\r
382 \r
383   //\r
384   // Create Hii Extend Label OpCode as the end opcode\r
385   //\r
386   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
387   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
388   EndLabel->Number       = LABEL_END;\r
389 \r
390   //\r
391   // Collect the languages from what our current Language support is based on our VFR\r
392   //\r
393   HiiHandle = gFrontPagePrivate.HiiHandle;\r
394   LanguageString = HiiGetSupportedLanguages (HiiHandle);\r
395   ASSERT (LanguageString != NULL);\r
396   //\r
397   // Allocate working buffer for RFC 4646 language in supported LanguageString.\r
398   //\r
399   Lang = AllocatePool (AsciiStrSize (LanguageString));\r
400   ASSERT (Lang != NULL);\r
401 \r
402   CurrentLang = GetEfiGlobalVariable (L"PlatformLang");\r
403   //\r
404   // Select the best language in LanguageString as the default one.\r
405   //\r
406   BestLanguage = GetBestLanguage (\r
407                    LanguageString,\r
408                    FALSE,\r
409                    (CurrentLang != NULL) ? CurrentLang : "",\r
410                    (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang),\r
411                    LanguageString,\r
412                    NULL\r
413                    );\r
414   //\r
415   // BestLanguage must be selected as it is the first language in LanguageString by default\r
416   //\r
417   ASSERT (BestLanguage != NULL);\r
418 \r
419   OptionCount = 0;\r
420   LangCode    = LanguageString;\r
421   FirstFlag   = FALSE;\r
422 \r
423   if (gFrontPagePrivate.LanguageToken == NULL) {\r
424     while (*LangCode != 0) {\r
425       GetNextLanguage (&LangCode, Lang);\r
426       OptionCount ++;\r
427     }\r
428     gFrontPagePrivate.LanguageToken = AllocatePool ((OptionCount + 1) * sizeof (EFI_STRING_ID));\r
429     ASSERT (gFrontPagePrivate.LanguageToken != NULL);\r
430     FirstFlag = TRUE;\r
431   }\r
432 \r
433   Status = gHiiString->NewString (gHiiString, HiiHandle, &Temp, "de-DE", L"Dedede", L"TEST", NULL);\r
434 \r
435   OptionCount = 0;\r
436   LangCode = LanguageString;\r
437   while (*LangCode != 0) {\r
438     GetNextLanguage (&LangCode, Lang);\r
439 \r
440     if (FirstFlag) {\r
441       StringBuffer = HiiGetString (HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, Lang);\r
442       ASSERT_EFI_ERROR (StringBuffer != NULL);\r
443 \r
444       //\r
445       // Save the string Id for each language\r
446       //\r
447       gFrontPagePrivate.LanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);\r
448       FreePool (StringBuffer);\r
449     }\r
450 \r
451     if (AsciiStrCmp (Lang, BestLanguage) == 0) {\r
452       HiiCreateOneOfOptionOpCode (\r
453         OptionsOpCodeHandle,\r
454         gFrontPagePrivate.LanguageToken[OptionCount],\r
455         EFI_IFR_OPTION_DEFAULT,\r
456         EFI_IFR_NUMERIC_SIZE_1,\r
457         (UINT8) OptionCount\r
458         );\r
459     } else {\r
460       HiiCreateOneOfOptionOpCode (\r
461         OptionsOpCodeHandle,\r
462         gFrontPagePrivate.LanguageToken[OptionCount],\r
463         0,\r
464         EFI_IFR_NUMERIC_SIZE_1,\r
465         (UINT8) OptionCount\r
466         );\r
467     }\r
468 \r
469     OptionCount++;\r
470   }\r
471 \r
472   if (CurrentLang != NULL) {\r
473     FreePool (CurrentLang);\r
474   }\r
475   FreePool (BestLanguage);\r
476   FreePool (Lang);\r
477   FreePool (LanguageString);\r
478 \r
479   HiiCreateOneOfOpCode (\r
480     StartOpCodeHandle,\r
481     FRONT_PAGE_KEY_LANGUAGE,\r
482     0,\r
483     0,\r
484     STRING_TOKEN (STR_LANGUAGE_SELECT),\r
485     STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),\r
486     EFI_IFR_FLAG_CALLBACK,\r
487     EFI_IFR_NUMERIC_SIZE_1,\r
488     OptionsOpCodeHandle,\r
489     NULL\r
490     );\r
491 \r
492   Status = HiiUpdateForm (\r
493              HiiHandle,\r
494              &mFrontPageGuid,\r
495              FRONT_PAGE_FORM_ID,\r
496              StartOpCodeHandle, // LABEL_SELECT_LANGUAGE\r
497              EndOpCodeHandle    // LABEL_END\r
498              );\r
499 \r
500   HiiFreeOpCodeHandle (StartOpCodeHandle);\r
501   HiiFreeOpCodeHandle (EndOpCodeHandle);\r
502   HiiFreeOpCodeHandle (OptionsOpCodeHandle);\r
503   return Status;\r
504 }\r
505 \r
506 /**\r
507   Call the browser and display the front page\r
508 \r
509   @return   Status code that will be returned by\r
510             EFI_FORM_BROWSER2_PROTOCOL.SendForm ().\r
511 \r
512 **/\r
513 EFI_STATUS\r
514 CallFrontPage (\r
515   VOID\r
516   )\r
517 {\r
518   EFI_STATUS                  Status;\r
519   EFI_BROWSER_ACTION_REQUEST  ActionRequest;\r
520 \r
521   //\r
522   // Begin waiting for USER INPUT\r
523   //\r
524   REPORT_STATUS_CODE (\r
525     EFI_PROGRESS_CODE,\r
526     (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_INPUT_WAIT)\r
527     );\r
528 \r
529   ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
530   Status = gFormBrowser2->SendForm (\r
531                             gFormBrowser2,\r
532                             &gFrontPagePrivate.HiiHandle,\r
533                             1,\r
534                             &mFrontPageGuid,\r
535                             0,\r
536                             NULL,\r
537                             &ActionRequest\r
538                             );\r
539   //\r
540   // Check whether user change any option setting which needs a reset to be effective\r
541   //\r
542   if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {\r
543     EnableResetRequired ();\r
544   }\r
545 \r
546   return Status;\r
547 }\r
548 \r
549 /**\r
550   Acquire the string associated with the ProducerGuid and return it.\r
551 \r
552 \r
553   @param ProducerGuid    The Guid to search the HII database for\r
554   @param Token           The token value of the string to extract\r
555   @param String          The string that is extracted\r
556 \r
557   @retval  EFI_SUCCESS  The function returns EFI_SUCCESS always.\r
558 \r
559 **/\r
560 EFI_STATUS\r
561 GetProducerString (\r
562   IN      EFI_GUID                  *ProducerGuid,\r
563   IN      EFI_STRING_ID             Token,\r
564   OUT     CHAR16                    **String\r
565   )\r
566 {\r
567   EFI_STRING      TmpString;\r
568 \r
569   TmpString = HiiGetPackageString (ProducerGuid, Token, NULL);\r
570   if (TmpString == NULL) {\r
571     *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));\r
572   } else {\r
573     *String = TmpString;\r
574   }\r
575 \r
576   return EFI_SUCCESS;\r
577 }\r
578 \r
579 /**\r
580   Convert Processor Frequency Data to a string.\r
581 \r
582   @param ProcessorFrequency The frequency data to process\r
583   @param Base10Exponent     The exponent based on 10\r
584   @param String             The string that is created\r
585 \r
586 **/\r
587 VOID\r
588 ConvertProcessorToString (\r
589   IN  UINT16                               ProcessorFrequency,\r
590   IN  UINT16                               Base10Exponent,\r
591   OUT CHAR16                               **String\r
592   )\r
593 {\r
594   CHAR16  *StringBuffer;\r
595   UINTN   Index;\r
596   UINT32  FreqMhz;\r
597 \r
598   if (Base10Exponent >= 6) {\r
599     FreqMhz = ProcessorFrequency;\r
600     for (Index = 0; Index < (UINTN) (Base10Exponent - 6); Index++) {\r
601       FreqMhz *= 10;\r
602     }\r
603   } else {\r
604     FreqMhz = 0;\r
605   }\r
606 \r
607   StringBuffer = AllocateZeroPool (0x20);\r
608   ASSERT (StringBuffer != NULL);\r
609   Index = UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, FreqMhz / 1000, 3);\r
610   StrCat (StringBuffer, L".");\r
611   UnicodeValueToString (StringBuffer + Index + 1, PREFIX_ZERO, (FreqMhz % 1000) / 10, 2);\r
612   StrCat (StringBuffer, L" GHz");\r
613   *String = (CHAR16 *) StringBuffer;\r
614   return ;\r
615 }\r
616 \r
617 \r
618 /**\r
619   Convert Memory Size to a string.\r
620 \r
621   @param MemorySize      The size of the memory to process\r
622   @param String          The string that is created\r
623 \r
624 **/\r
625 VOID\r
626 ConvertMemorySizeToString (\r
627   IN  UINT32          MemorySize,\r
628   OUT CHAR16          **String\r
629   )\r
630 {\r
631   CHAR16  *StringBuffer;\r
632 \r
633   StringBuffer = AllocateZeroPool (0x20);\r
634   ASSERT (StringBuffer != NULL);\r
635   UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, MemorySize, 6);\r
636   StrCat (StringBuffer, L" MB RAM");\r
637 \r
638   *String = (CHAR16 *) StringBuffer;\r
639 \r
640   return ;\r
641 }\r
642 \r
643 /**\r
644 \r
645   Acquire the string associated with the Index from smbios structure and return it.\r
646   The caller is responsible for free the string buffer.\r
647 \r
648   @param    OptionalStrStart  The start position to search the string\r
649   @param    Index             The index of the string to extract\r
650   @param    String            The string that is extracted\r
651 \r
652   @retval   EFI_SUCCESS       The function returns EFI_SUCCESS always.\r
653 \r
654 **/\r
655 EFI_STATUS\r
656 GetOptionalStringByIndex (\r
657   IN      CHAR8                   *OptionalStrStart,\r
658   IN      UINT8                   Index,\r
659   OUT     CHAR16                  **String\r
660   )\r
661 {\r
662   UINT8          StrNum;\r
663   UINTN          CurrentStrLen;\r
664   CHAR8*         CharInStr;\r
665   EFI_STATUS     Status;\r
666 \r
667   StrNum        = 0;\r
668   Status        = EFI_NOT_FOUND;\r
669   CharInStr     = OptionalStrStart;\r
670 \r
671   if (Index != 1) {\r
672     CurrentStrLen = 0;\r
673     //\r
674     // look for the two consecutive zeros, check the string limit by the way.\r
675     //\r
676     while (*CharInStr != 0 || *(CharInStr+1) != 0) { \r
677       if (*CharInStr == 0) {\r
678         StrNum += 1;\r
679         CharInStr++;\r
680       }\r
681   \r
682       if (StrNum == Index) {\r
683         Status = EFI_SUCCESS;\r
684         break;\r
685       }\r
686   \r
687       CurrentStrLen = AsciiStrLen(CharInStr);\r
688   \r
689       //\r
690       // forward the pointer\r
691       //\r
692       OptionalStrStart = CharInStr;\r
693       CharInStr += CurrentStrLen;\r
694     }\r
695   \r
696     if (EFI_ERROR (Status)) {\r
697       *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));\r
698       return Status;\r
699     }\r
700   } else {\r
701     CurrentStrLen = AsciiStrLen(CharInStr);\r
702   }\r
703 \r
704   *String = AllocatePool((CurrentStrLen + 1)*sizeof(CHAR16));\r
705   AsciiStrToUnicodeStr(OptionalStrStart, *String);\r
706 \r
707   return EFI_SUCCESS;\r
708 }\r
709 \r
710 \r
711 /**\r
712   Update the banner information for the Front Page based on DataHub information.\r
713 \r
714 **/\r
715 VOID\r
716 UpdateFrontPageStrings (\r
717   VOID\r
718   )\r
719 {\r
720   UINT8                             StrIndex;\r
721   CHAR16                            *NewString;\r
722   BOOLEAN                           Find[5];\r
723   EFI_STATUS                        Status;\r
724   EFI_STRING_ID                     TokenToUpdate;\r
725   EFI_SMBIOS_HANDLE                 SmbiosHandle;\r
726   EFI_SMBIOS_PROTOCOL               *Smbios;\r
727   SMBIOS_TABLE_TYPE0                *Type0Record;\r
728   SMBIOS_TABLE_TYPE1                *Type1Record;\r
729   SMBIOS_TABLE_TYPE4                *Type4Record;\r
730   SMBIOS_TABLE_TYPE19               *Type19Record;\r
731   EFI_SMBIOS_TABLE_HEADER           *Record;\r
732 \r
733   ZeroMem (Find, sizeof (Find));\r
734 \r
735   //\r
736   // Update Front Page strings\r
737   //\r
738   Status = gBS->LocateProtocol (\r
739                   &gEfiSmbiosProtocolGuid,\r
740                   NULL,\r
741                   (VOID **) &Smbios\r
742                   );\r
743   ASSERT_EFI_ERROR (Status);\r
744 \r
745   SmbiosHandle = 0;\r
746   do {\r
747     Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);\r
748     if (EFI_ERROR(Status)) {\r
749       break;\r
750     }\r
751 \r
752     if (Record->Type == EFI_SMBIOS_TYPE_BIOS_INFORMATION) {\r
753       Type0Record = (SMBIOS_TABLE_TYPE0 *) Record;\r
754       StrIndex = Type0Record->BiosVersion;\r
755       GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type0Record + Type0Record->Hdr.Length), StrIndex, &NewString);\r
756       TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION);\r
757       HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);\r
758       FreePool (NewString);\r
759       Find[0] = TRUE;\r
760     }  \r
761 \r
762     if (Record->Type == EFI_SMBIOS_TYPE_SYSTEM_INFORMATION) {\r
763       Type1Record = (SMBIOS_TABLE_TYPE1 *) Record;\r
764       StrIndex = Type1Record->ProductName;\r
765       GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);\r
766       TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL);\r
767       HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);\r
768       FreePool (NewString);\r
769       Find[1] = TRUE;\r
770     }\r
771       \r
772     if (Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) {\r
773       Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;\r
774       StrIndex = Type4Record->ProcessorVersion;\r
775       GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString);\r
776       TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL);\r
777       HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);\r
778       FreePool (NewString);\r
779       Find[2] = TRUE;\r
780     }    \r
781 \r
782     if (Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) {\r
783       Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;\r
784       ConvertProcessorToString(Type4Record->CurrentSpeed, 6, &NewString);\r
785       TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED);\r
786       HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);\r
787       FreePool (NewString);\r
788       Find[3] = TRUE;\r
789     } \r
790 \r
791     if ( Record->Type == EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS ) {\r
792       Type19Record = (SMBIOS_TABLE_TYPE19 *) Record;\r
793       ConvertMemorySizeToString (\r
794         (UINT32)(RShiftU64((Type19Record->EndingAddress - Type19Record->StartingAddress + 1), 10)),\r
795         &NewString\r
796         );\r
797       TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE);\r
798       HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);\r
799       FreePool (NewString);\r
800       Find[4] = TRUE;  \r
801     }\r
802   } while ( !(Find[0] && Find[1] && Find[2] && Find[3] && Find[4]));\r
803   return ;\r
804 }\r
805 \r
806 \r
807 /**\r
808   Function waits for a given event to fire, or for an optional timeout to expire.\r
809 \r
810   @param   Event              The event to wait for\r
811   @param   Timeout            An optional timeout value in 100 ns units.\r
812 \r
813   @retval  EFI_SUCCESS      Event fired before Timeout expired.\r
814   @retval  EFI_TIME_OUT     Timout expired before Event fired..\r
815 \r
816 **/\r
817 EFI_STATUS\r
818 WaitForSingleEvent (\r
819   IN EFI_EVENT                  Event,\r
820   IN UINT64                     Timeout OPTIONAL\r
821   )\r
822 {\r
823   UINTN       Index;\r
824   EFI_STATUS  Status;\r
825   EFI_EVENT   TimerEvent;\r
826   EFI_EVENT   WaitList[2];\r
827 \r
828   if (Timeout != 0) {\r
829     //\r
830     // Create a timer event\r
831     //\r
832     Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);\r
833     if (!EFI_ERROR (Status)) {\r
834       //\r
835       // Set the timer event\r
836       //\r
837       gBS->SetTimer (\r
838              TimerEvent,\r
839              TimerRelative,\r
840              Timeout\r
841              );\r
842 \r
843       //\r
844       // Wait for the original event or the timer\r
845       //\r
846       WaitList[0] = Event;\r
847       WaitList[1] = TimerEvent;\r
848       Status      = gBS->WaitForEvent (2, WaitList, &Index);\r
849       gBS->CloseEvent (TimerEvent);\r
850 \r
851       //\r
852       // If the timer expired, change the return to timed out\r
853       //\r
854       if (!EFI_ERROR (Status) && Index == 1) {\r
855         Status = EFI_TIMEOUT;\r
856       }\r
857     }\r
858   } else {\r
859     //\r
860     // No timeout... just wait on the event\r
861     //\r
862     Status = gBS->WaitForEvent (1, &Event, &Index);\r
863     ASSERT (!EFI_ERROR (Status));\r
864     ASSERT (Index == 0);\r
865   }\r
866 \r
867   return Status;\r
868 }\r
869 \r
870 /**\r
871   Function show progress bar to wait for user input.\r
872 \r
873 \r
874   @param   TimeoutDefault  The fault time out value before the system continue to boot.\r
875 \r
876   @retval  EFI_SUCCESS       User pressed some key except "Enter"\r
877   @retval  EFI_TIME_OUT      Timeout expired or user press "Enter"\r
878 \r
879 **/\r
880 EFI_STATUS\r
881 ShowProgress (\r
882   IN UINT16                       TimeoutDefault\r
883   )\r
884 {\r
885   CHAR16                        *TmpStr;\r
886   UINT16                        TimeoutRemain;\r
887   EFI_STATUS                    Status;\r
888   EFI_INPUT_KEY                 Key;\r
889   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;\r
890   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;\r
891   EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;\r
892 \r
893   if (TimeoutDefault == 0) {\r
894     return EFI_TIMEOUT;\r
895   }\r
896 \r
897   DEBUG ((EFI_D_INFO, "\n\nStart showing progress bar... Press any key to stop it! ...Zzz....\n"));\r
898 \r
899   SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);\r
900   SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);\r
901   SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);\r
902 \r
903   //\r
904   // Clear the progress status bar first\r
905   //\r
906   TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION));\r
907   if (TmpStr != NULL) {\r
908     PlatformBdsShowProgress (Foreground, Background, TmpStr, Color, 0, 0);\r
909   }\r
910 \r
911   TimeoutRemain = TimeoutDefault;\r
912   while (TimeoutRemain != 0) {\r
913     DEBUG ((EFI_D_INFO, "Showing progress bar...Remaining %d second!\n", TimeoutRemain));\r
914 \r
915     Status = WaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);\r
916     if (Status != EFI_TIMEOUT) {\r
917       break;\r
918     }\r
919     TimeoutRemain--;\r
920 \r
921     //\r
922     // Show progress\r
923     //\r
924     if (TmpStr != NULL) {\r
925       PlatformBdsShowProgress (\r
926         Foreground,\r
927         Background,\r
928         TmpStr,\r
929         Color,\r
930         ((TimeoutDefault - TimeoutRemain) * 100 / TimeoutDefault),\r
931         0\r
932         );\r
933     }\r
934   }\r
935   gBS->FreePool (TmpStr);\r
936 \r
937   //\r
938   // Timeout expired\r
939   //\r
940   if (TimeoutRemain == 0) {\r
941     return EFI_TIMEOUT;\r
942   }\r
943 \r
944   //\r
945   // User pressed some key\r
946   //\r
947   Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
948   if (EFI_ERROR (Status)) {\r
949     return Status;\r
950   }\r
951 \r
952   if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {\r
953     //\r
954     // User pressed enter, equivalent to select "continue"\r
955     //\r
956     return EFI_TIMEOUT;\r
957   }\r
958 \r
959   return EFI_SUCCESS;\r
960 }\r
961 \r
962 /**\r
963   This function is the main entry of the platform setup entry.\r
964   The function will present the main menu of the system setup,\r
965   this is the platform reference part and can be customize.\r
966 \r
967 \r
968   @param TimeoutDefault     The fault time out value before the system\r
969                             continue to boot.\r
970   @param ConnectAllHappened The indicater to check if the connect all have\r
971                             already happened.\r
972 \r
973 **/\r
974 VOID\r
975 PlatformBdsEnterFrontPage (\r
976   IN UINT16                       TimeoutDefault,\r
977   IN BOOLEAN                      ConnectAllHappened\r
978   )\r
979 {\r
980   EFI_STATUS                    Status;\r
981 \r
982   PERF_START (NULL, "BdsTimeOut", "BDS", 0);\r
983   //\r
984   // Indicate if we need connect all in the platform setup\r
985   //\r
986   if (ConnectAllHappened) {\r
987     gConnectAllHappened = TRUE;\r
988   }\r
989 \r
990   if (TimeoutDefault != 0xffff) {\r
991     Status = ShowProgress (TimeoutDefault);\r
992 \r
993     //\r
994     // Ensure screen is clear when switch Console from Graphics mode to Text mode\r
995     //\r
996     gST->ConOut->EnableCursor (gST->ConOut, TRUE);\r
997     gST->ConOut->ClearScreen (gST->ConOut);\r
998 \r
999     if (EFI_ERROR (Status)) {\r
1000       //\r
1001       // Timeout or user press enter to continue\r
1002       //\r
1003       goto Exit;\r
1004     }\r
1005   }\r
1006 \r
1007   do {\r
1008 \r
1009     InitializeFrontPage (FALSE);\r
1010 \r
1011     //\r
1012     // Update Front Page strings\r
1013     //\r
1014     UpdateFrontPageStrings ();\r
1015 \r
1016     gCallbackKey = 0;\r
1017     Status = CallFrontPage ();\r
1018 \r
1019     //\r
1020     // If gCallbackKey is greater than 1 and less or equal to 5,\r
1021     // it will launch configuration utilities.\r
1022     // 2 = set language\r
1023     // 3 = boot manager\r
1024     // 4 = device manager\r
1025     // 5 = boot maintenance manager\r
1026     //\r
1027     if (gCallbackKey != 0) {\r
1028       REPORT_STATUS_CODE (\r
1029         EFI_PROGRESS_CODE,\r
1030         (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP)\r
1031         );\r
1032     }\r
1033     //\r
1034     // Based on the key that was set, we can determine what to do\r
1035     //\r
1036     switch (gCallbackKey) {\r
1037     //\r
1038     // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can\r
1039     // describe to their customers in documentation how to find their setup information (namely\r
1040     // under the device manager and specific buckets)\r
1041     //\r
1042     // These entries consist of the Continue, Select language, Boot Manager, and Device Manager\r
1043     //\r
1044     case FRONT_PAGE_KEY_CONTINUE:\r
1045       //\r
1046       // User hit continue\r
1047       //\r
1048       break;\r
1049 \r
1050     case FRONT_PAGE_KEY_LANGUAGE:\r
1051       //\r
1052       // User made a language setting change - display front page again\r
1053       //\r
1054       break;\r
1055 \r
1056     case FRONT_PAGE_KEY_BOOT_MANAGER:\r
1057       //\r
1058       // User chose to run the Boot Manager\r
1059       //\r
1060       CallBootManager ();\r
1061       break;\r
1062 \r
1063     case FRONT_PAGE_KEY_DEVICE_MANAGER:\r
1064       //\r
1065       // Display the Device Manager\r
1066       //\r
1067       do {\r
1068         CallDeviceManager ();\r
1069       } while (gCallbackKey == FRONT_PAGE_KEY_DEVICE_MANAGER);\r
1070       break;\r
1071 \r
1072     case FRONT_PAGE_KEY_BOOT_MAINTAIN:\r
1073       //\r
1074       // Display the Boot Maintenance Manager\r
1075       //\r
1076       BdsStartBootMaint ();\r
1077       break;\r
1078     }\r
1079 \r
1080   } while ((Status == EFI_SUCCESS) && (gCallbackKey != FRONT_PAGE_KEY_CONTINUE));\r
1081 \r
1082   //\r
1083   //Will leave browser, check any reset required change is applied? if yes, reset system\r
1084   //\r
1085   SetupResetReminder ();\r
1086 \r
1087 Exit:\r
1088   //\r
1089   // Automatically load current entry\r
1090   // Note: The following lines of code only execute when Auto boot\r
1091   // takes affect\r
1092   //\r
1093   PERF_END (NULL, "BdsTimeOut", "BDS", 0);\r
1094 }\r