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