]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c
MdeModulePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdeModulePkg / Application / UiApp / FrontPageCustomizedUiSupport.c
1 /** @file
2
3 This library class defines a set of interfaces to customize Ui module
4
5 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9 #include <Uefi.h>
10
11 #include <Guid/MdeModuleHii.h>
12 #include <Guid/GlobalVariable.h>
13
14 #include <Protocol/HiiConfigAccess.h>
15 #include <Protocol/HiiString.h>
16
17 #include <Library/HiiLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/UefiLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/PcdLib.h>
22 #include <Library/MemoryAllocationLib.h>
23 #include <Library/UefiRuntimeServicesTableLib.h>
24 #include <Library/UefiHiiServicesLib.h>
25 #include <Library/DevicePathLib.h>
26 #include <Library/UefiBootServicesTableLib.h>
27 #include "FrontPageCustomizedUiSupport.h"
28
29 //
30 // This is the VFR compiler generated header file which defines the
31 // string identifiers.
32 //
33 #define PRINTABLE_LANGUAGE_NAME_STRING_ID 0x0001
34
35 #define UI_HII_DRIVER_LIST_SIZE 0x8
36
37 #define FRONT_PAGE_KEY_CONTINUE 0x1000
38 #define FRONT_PAGE_KEY_RESET 0x1001
39 #define FRONT_PAGE_KEY_LANGUAGE 0x1002
40 #define FRONT_PAGE_KEY_DRIVER 0x2000
41
42 typedef struct {
43 EFI_STRING_ID PromptId;
44 EFI_STRING_ID HelpId;
45 EFI_STRING_ID DevicePathId;
46 EFI_GUID FormSetGuid;
47 BOOLEAN EmptyLineAfter;
48 } UI_HII_DRIVER_INSTANCE;
49
50 CHAR8 *gLanguageString;
51 EFI_STRING_ID *gLanguageToken;
52 UI_HII_DRIVER_INSTANCE *gHiiDriverList;
53 extern EFI_HII_HANDLE gStringPackHandle;
54 UINT8 gCurrentLanguageIndex;
55
56
57 /**
58 Get next language from language code list (with separator ';').
59
60 If LangCode is NULL, then ASSERT.
61 If Lang is NULL, then ASSERT.
62
63 @param LangCode On input: point to first language in the list. On
64 output: point to next language in the list, or
65 NULL if no more language in the list.
66 @param Lang The first language in the list.
67
68 **/
69 VOID
70 GetNextLanguage (
71 IN OUT CHAR8 **LangCode,
72 OUT CHAR8 *Lang
73 )
74 {
75 UINTN Index;
76 CHAR8 *StringPtr;
77
78 ASSERT (LangCode != NULL);
79 ASSERT (*LangCode != NULL);
80 ASSERT (Lang != NULL);
81
82 Index = 0;
83 StringPtr = *LangCode;
84 while (StringPtr[Index] != 0 && StringPtr[Index] != ';') {
85 Index++;
86 }
87
88 CopyMem (Lang, StringPtr, Index);
89 Lang[Index] = 0;
90
91 if (StringPtr[Index] == ';') {
92 Index++;
93 }
94 *LangCode = StringPtr + Index;
95 }
96
97 /**
98 This function processes the language changes in configuration.
99
100 @param Value A pointer to the data being sent to the original exporting driver.
101
102
103 @retval TRUE The callback successfully handled the action.
104 @retval FALSE The callback not supported in this handler.
105
106 **/
107 EFI_STATUS
108 LanguageChangeHandler (
109 IN EFI_IFR_TYPE_VALUE *Value
110 )
111 {
112 CHAR8 *LangCode;
113 CHAR8 *Lang;
114 UINTN Index;
115 EFI_STATUS Status;
116
117 //
118 // Allocate working buffer for RFC 4646 language in supported LanguageString.
119 //
120 Lang = AllocatePool (AsciiStrSize (gLanguageString));
121 ASSERT (Lang != NULL);
122
123 Index = 0;
124 LangCode = gLanguageString;
125 while (*LangCode != 0) {
126 GetNextLanguage (&LangCode, Lang);
127
128 if (Index == Value->u8) {
129 gCurrentLanguageIndex = Value->u8;
130 break;
131 }
132
133 Index++;
134 }
135
136 if (Index == Value->u8) {
137 Status = gRT->SetVariable (
138 L"PlatformLang",
139 &gEfiGlobalVariableGuid,
140 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
141 AsciiStrSize (Lang),
142 Lang
143 );
144 if (EFI_ERROR (Status)) {
145 FreePool (Lang);
146 return EFI_DEVICE_ERROR;
147 }
148 } else {
149 ASSERT (FALSE);
150 }
151 FreePool (Lang);
152
153 return EFI_SUCCESS;
154 }
155
156 /**
157 This function processes the results of changes in configuration.
158
159
160 @param HiiHandle Points to the hii handle for this formset.
161 @param Action Specifies the type of action taken by the browser.
162 @param QuestionId A unique value which is sent to the original exporting driver
163 so that it can identify the type of data to expect.
164 @param Type The type of value for the question.
165 @param Value A pointer to the data being sent to the original exporting driver.
166 @param ActionRequest On return, points to the action requested by the callback function.
167 @param Status Return the handle status.
168
169 @retval TRUE The callback successfully handled the action.
170 @retval FALSE The callback not supported in this handler.
171
172 **/
173 BOOLEAN
174 UiSupportLibCallbackHandler (
175 IN EFI_HII_HANDLE HiiHandle,
176 IN EFI_BROWSER_ACTION Action,
177 IN EFI_QUESTION_ID QuestionId,
178 IN UINT8 Type,
179 IN EFI_IFR_TYPE_VALUE *Value,
180 OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest,
181 OUT EFI_STATUS *Status
182 )
183 {
184 if (QuestionId != FRONT_PAGE_KEY_CONTINUE &&
185 QuestionId != FRONT_PAGE_KEY_RESET &&
186 QuestionId != FRONT_PAGE_KEY_LANGUAGE) {
187 return FALSE;
188 }
189
190 if (Action == EFI_BROWSER_ACTION_RETRIEVE) {
191 if (QuestionId == FRONT_PAGE_KEY_LANGUAGE) {
192 Value->u8 = gCurrentLanguageIndex;
193 *Status = EFI_SUCCESS;
194 } else {
195 *Status = EFI_UNSUPPORTED;
196 }
197 return TRUE;
198 }
199
200 if (Action != EFI_BROWSER_ACTION_CHANGED) {
201 //
202 // Do nothing for other UEFI Action. Only do call back when data is changed.
203 //
204 *Status = EFI_UNSUPPORTED;
205 return TRUE;
206 }
207
208 if (Action == EFI_BROWSER_ACTION_CHANGED) {
209 if ((Value == NULL) || (ActionRequest == NULL)) {
210 *Status = EFI_INVALID_PARAMETER;
211 return TRUE;
212 }
213
214 *Status = EFI_SUCCESS;
215 switch (QuestionId) {
216 case FRONT_PAGE_KEY_CONTINUE:
217 //
218 // This is the continue - clear the screen and return an error to get out of FrontPage loop
219 //
220 *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
221 break;
222
223 case FRONT_PAGE_KEY_LANGUAGE:
224 *Status = LanguageChangeHandler(Value);
225 break;
226
227 case FRONT_PAGE_KEY_RESET:
228 //
229 // Reset
230 //
231 gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
232 *Status = EFI_UNSUPPORTED;
233
234 default:
235 break;
236 }
237 }
238
239 return TRUE;
240 }
241
242 /**
243 Create Select language menu in the front page with oneof opcode.
244
245 @param[in] HiiHandle The hii handle for the Uiapp driver.
246 @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
247
248 **/
249 VOID
250 UiCreateLanguageMenu (
251 IN EFI_HII_HANDLE HiiHandle,
252 IN VOID *StartOpCodeHandle
253 )
254 {
255 CHAR8 *LangCode;
256 CHAR8 *Lang;
257 UINTN LangSize;
258 CHAR8 *CurrentLang;
259 UINTN OptionCount;
260 CHAR16 *StringBuffer;
261 VOID *OptionsOpCodeHandle;
262 UINTN StringSize;
263 EFI_STATUS Status;
264 EFI_HII_STRING_PROTOCOL *HiiString;
265
266 Lang = NULL;
267 StringBuffer = NULL;
268
269 //
270 // Init OpCode Handle and Allocate space for creation of UpdateData Buffer
271 //
272 OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
273 ASSERT (OptionsOpCodeHandle != NULL);
274
275 GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL);
276
277 //
278 // Get Support language list from variable.
279 //
280 GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&gLanguageString, NULL);
281 if (gLanguageString == NULL) {
282 gLanguageString = AllocateCopyPool (
283 AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),
284 (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)
285 );
286 ASSERT (gLanguageString != NULL);
287 }
288
289 if (gLanguageToken == NULL) {
290 //
291 // Count the language list number.
292 //
293 LangCode = gLanguageString;
294 Lang = AllocatePool (AsciiStrSize (gLanguageString));
295 ASSERT (Lang != NULL);
296
297 OptionCount = 0;
298 while (*LangCode != 0) {
299 GetNextLanguage (&LangCode, Lang);
300 OptionCount ++;
301 }
302
303 //
304 // Allocate extra 1 as the end tag.
305 //
306 gLanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID));
307 ASSERT (gLanguageToken != NULL);
308
309 Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
310 ASSERT_EFI_ERROR (Status);
311
312 LangCode = gLanguageString;
313 OptionCount = 0;
314 while (*LangCode != 0) {
315 GetNextLanguage (&LangCode, Lang);
316
317 StringSize = 0;
318 Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
319 if (Status == EFI_BUFFER_TOO_SMALL) {
320 StringBuffer = AllocateZeroPool (StringSize);
321 ASSERT (StringBuffer != NULL);
322 Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
323 ASSERT_EFI_ERROR (Status);
324 }
325
326 if (EFI_ERROR (Status)) {
327 LangSize = AsciiStrSize (Lang);
328 StringBuffer = AllocatePool (LangSize * sizeof (CHAR16));
329 ASSERT (StringBuffer != NULL);
330 AsciiStrToUnicodeStrS (Lang, StringBuffer, LangSize);
331 }
332
333 ASSERT (StringBuffer != NULL);
334 gLanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);
335 FreePool (StringBuffer);
336
337 OptionCount++;
338 }
339 }
340
341 ASSERT (gLanguageToken != NULL);
342 LangCode = gLanguageString;
343 OptionCount = 0;
344 if (Lang == NULL) {
345 Lang = AllocatePool (AsciiStrSize (gLanguageString));
346 ASSERT (Lang != NULL);
347 }
348 while (*LangCode != 0) {
349 GetNextLanguage (&LangCode, Lang);
350
351 if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) {
352 HiiCreateOneOfOptionOpCode (
353 OptionsOpCodeHandle,
354 gLanguageToken[OptionCount],
355 EFI_IFR_OPTION_DEFAULT,
356 EFI_IFR_NUMERIC_SIZE_1,
357 (UINT8) OptionCount
358 );
359 gCurrentLanguageIndex = (UINT8) OptionCount;
360 } else {
361 HiiCreateOneOfOptionOpCode (
362 OptionsOpCodeHandle,
363 gLanguageToken[OptionCount],
364 0,
365 EFI_IFR_NUMERIC_SIZE_1,
366 (UINT8) OptionCount
367 );
368 }
369
370 OptionCount++;
371 }
372
373 if (CurrentLang != NULL) {
374 FreePool (CurrentLang);
375 }
376 FreePool (Lang);
377
378 HiiCreateOneOfOpCode (
379 StartOpCodeHandle,
380 FRONT_PAGE_KEY_LANGUAGE,
381 0,
382 0,
383 STRING_TOKEN (STR_LANGUAGE_SELECT),
384 STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),
385 EFI_IFR_FLAG_CALLBACK,
386 EFI_IFR_NUMERIC_SIZE_1,
387 OptionsOpCodeHandle,
388 NULL
389 );
390 }
391
392 /**
393 Create continue menu in the front page.
394
395 @param[in] HiiHandle The hii handle for the Uiapp driver.
396 @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
397
398 **/
399 VOID
400 UiCreateContinueMenu (
401 IN EFI_HII_HANDLE HiiHandle,
402 IN VOID *StartOpCodeHandle
403 )
404 {
405 HiiCreateActionOpCode (
406 StartOpCodeHandle,
407 FRONT_PAGE_KEY_CONTINUE,
408 STRING_TOKEN (STR_CONTINUE_PROMPT),
409 STRING_TOKEN (STR_CONTINUE_PROMPT),
410 EFI_IFR_FLAG_CALLBACK,
411 0
412 );
413 }
414
415 /**
416 Create empty line menu in the front page.
417
418 @param HiiHandle The hii handle for the Uiapp driver.
419 @param StartOpCodeHandle The opcode handle to save the new opcode.
420
421 **/
422 VOID
423 UiCreateEmptyLine (
424 IN EFI_HII_HANDLE HiiHandle,
425 IN VOID *StartOpCodeHandle
426 )
427 {
428 HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_NULL_STRING), 0, 0, 0);
429 }
430
431 /**
432 Create Reset menu in the front page.
433
434 @param[in] HiiHandle The hii handle for the Uiapp driver.
435 @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
436
437 **/
438 VOID
439 UiCreateResetMenu (
440 IN EFI_HII_HANDLE HiiHandle,
441 IN VOID *StartOpCodeHandle
442 )
443 {
444 HiiCreateActionOpCode (
445 StartOpCodeHandle,
446 FRONT_PAGE_KEY_RESET,
447 STRING_TOKEN (STR_RESET_STRING),
448 STRING_TOKEN (STR_RESET_STRING),
449 EFI_IFR_FLAG_CALLBACK,
450 0
451 );
452 }
453
454 /**
455 Extract device path for given HII handle and class guid.
456
457 @param Handle The HII handle.
458
459 @retval NULL Fail to get the device path string.
460 @return PathString Get the device path string.
461
462 **/
463 CHAR16 *
464 ExtractDevicePathFromHiiHandle (
465 IN EFI_HII_HANDLE Handle
466 )
467 {
468 EFI_STATUS Status;
469 EFI_HANDLE DriverHandle;
470
471 ASSERT (Handle != NULL);
472
473 if (Handle == NULL) {
474 return NULL;
475 }
476
477 Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
478 if (EFI_ERROR (Status)) {
479 return NULL;
480 }
481
482 return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE);
483 }
484
485 /**
486 Check whether this driver need to be shown in the front page.
487
488 @param HiiHandle The hii handle for the driver.
489 @param Guid The special guid for the driver which is the target.
490 @param PromptId Return the prompt string id.
491 @param HelpId Return the help string id.
492 @param FormsetGuid Return the formset guid info.
493
494 @retval EFI_SUCCESS Search the driver success
495
496 **/
497 BOOLEAN
498 RequiredDriver (
499 IN EFI_HII_HANDLE HiiHandle,
500 IN EFI_GUID *Guid,
501 OUT EFI_STRING_ID *PromptId,
502 OUT EFI_STRING_ID *HelpId,
503 OUT VOID *FormsetGuid
504 )
505 {
506 EFI_STATUS Status;
507 UINT8 ClassGuidNum;
508 EFI_GUID *ClassGuid;
509 EFI_IFR_FORM_SET *Buffer;
510 UINTN BufferSize;
511 UINT8 *Ptr;
512 UINTN TempSize;
513 BOOLEAN RetVal;
514
515 Status = HiiGetFormSetFromHiiHandle(HiiHandle, &Buffer,&BufferSize);
516 if (EFI_ERROR (Status)) {
517 return FALSE;
518 }
519
520 RetVal = FALSE;
521 TempSize = 0;
522 Ptr = (UINT8 *) Buffer;
523 while(TempSize < BufferSize) {
524 TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
525
526 if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){
527 Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
528 continue;
529 }
530
531 ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3);
532 ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET));
533 while (ClassGuidNum-- > 0) {
534 if (!CompareGuid (Guid, ClassGuid)){
535 ClassGuid ++;
536 continue;
537 }
538
539 *PromptId = ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle;
540 *HelpId = ((EFI_IFR_FORM_SET *)Ptr)->Help;
541 CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) Ptr)->Guid, sizeof (EFI_GUID));
542 RetVal = TRUE;
543 }
544 }
545
546 FreePool (Buffer);
547
548 return RetVal;
549 }
550
551 /**
552 Search the drivers in the system which need to show in the front page
553 and insert the menu to the front page.
554
555 @param HiiHandle The hii handle for the Uiapp driver.
556 @param ClassGuid The class guid for the driver which is the target.
557 @param SpecialHandlerFn The pointer to the specail handler function, if any.
558 @param StartOpCodeHandle The opcode handle to save the new opcode.
559
560 @retval EFI_SUCCESS Search the driver success
561
562 **/
563 EFI_STATUS
564 UiListThirdPartyDrivers (
565 IN EFI_HII_HANDLE HiiHandle,
566 IN EFI_GUID *ClassGuid,
567 IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn,
568 IN VOID *StartOpCodeHandle
569 )
570 {
571 UINTN Index;
572 EFI_STRING String;
573 EFI_STRING_ID Token;
574 EFI_STRING_ID TokenHelp;
575 EFI_HII_HANDLE *HiiHandles;
576 CHAR16 *DevicePathStr;
577 UINTN Count;
578 UINTN CurrentSize;
579 UI_HII_DRIVER_INSTANCE *DriverListPtr;
580 EFI_STRING NewName;
581 BOOLEAN EmptyLineAfter;
582
583 if (gHiiDriverList != NULL) {
584 FreePool (gHiiDriverList);
585 }
586
587 HiiHandles = HiiGetHiiHandles (NULL);
588 ASSERT (HiiHandles != NULL);
589
590 gHiiDriverList = AllocateZeroPool (UI_HII_DRIVER_LIST_SIZE * sizeof (UI_HII_DRIVER_INSTANCE));
591 ASSERT (gHiiDriverList != NULL);
592 DriverListPtr = gHiiDriverList;
593 CurrentSize = UI_HII_DRIVER_LIST_SIZE;
594
595 for (Index = 0, Count = 0; HiiHandles[Index] != NULL; Index++) {
596 if (!RequiredDriver (HiiHandles[Index], ClassGuid, &Token, &TokenHelp, &gHiiDriverList[Count].FormSetGuid)) {
597 continue;
598 }
599
600 String = HiiGetString (HiiHandles[Index], Token, NULL);
601 if (String == NULL) {
602 String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
603 ASSERT (String != NULL);
604 } else if (SpecialHandlerFn != NULL) {
605 //
606 // Check whether need to rename the driver name.
607 //
608 EmptyLineAfter = FALSE;
609 if (SpecialHandlerFn (String, &NewName, &EmptyLineAfter)) {
610 FreePool (String);
611 String = NewName;
612 DriverListPtr[Count].EmptyLineAfter = EmptyLineAfter;
613 }
614 }
615 DriverListPtr[Count].PromptId = HiiSetString (HiiHandle, 0, String, NULL);
616 FreePool (String);
617
618 String = HiiGetString (HiiHandles[Index], TokenHelp, NULL);
619 if (String == NULL) {
620 String = HiiGetString (gStringPackHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
621 ASSERT (String != NULL);
622 }
623 DriverListPtr[Count].HelpId = HiiSetString (HiiHandle, 0, String, NULL);
624 FreePool (String);
625
626 DevicePathStr = ExtractDevicePathFromHiiHandle(HiiHandles[Index]);
627 if (DevicePathStr != NULL){
628 DriverListPtr[Count].DevicePathId = HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
629 FreePool (DevicePathStr);
630 } else {
631 DriverListPtr[Count].DevicePathId = 0;
632 }
633
634 Count++;
635 if (Count >= CurrentSize) {
636 DriverListPtr = ReallocatePool (
637 CurrentSize * sizeof (UI_HII_DRIVER_INSTANCE),
638 (Count + UI_HII_DRIVER_LIST_SIZE)
639 * sizeof (UI_HII_DRIVER_INSTANCE),
640 gHiiDriverList
641 );
642 ASSERT (DriverListPtr != NULL);
643 gHiiDriverList = DriverListPtr;
644 CurrentSize += UI_HII_DRIVER_LIST_SIZE;
645 }
646 }
647
648 FreePool (HiiHandles);
649
650 Index = 0;
651 while (gHiiDriverList[Index].PromptId != 0) {
652 HiiCreateGotoExOpCode (
653 StartOpCodeHandle,
654 0,
655 gHiiDriverList[Index].PromptId,
656 gHiiDriverList[Index].HelpId,
657 0,
658 (EFI_QUESTION_ID) (Index + FRONT_PAGE_KEY_DRIVER),
659 0,
660 &gHiiDriverList[Index].FormSetGuid,
661 gHiiDriverList[Index].DevicePathId
662 );
663
664 if (gHiiDriverList[Index].EmptyLineAfter) {
665 UiCreateEmptyLine (HiiHandle, StartOpCodeHandle);
666 }
667
668 Index ++;
669 }
670
671 return EFI_SUCCESS;
672 }