]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/UiApp/FrontPageCustomizedUiSupport.c
MdeModulePkg/UiApp: Exit function when parameter is unsupported or invalid
[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] QuestionId Question ID
240 @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
241
242 @retval EFI_SUCCESS Search the driver success
243
244 **/
245 VOID
246 UiCreateLanguageMenu (
247 IN EFI_HII_HANDLE HiiHandle,
248 IN VOID *StartOpCodeHandle
249 )
250 {
251 CHAR8 *LangCode;
252 CHAR8 *Lang;
253 CHAR8 *CurrentLang;
254 UINTN OptionCount;
255 CHAR16 *StringBuffer;
256 VOID *OptionsOpCodeHandle;
257 UINTN StringSize;
258 EFI_STATUS Status;
259 EFI_HII_STRING_PROTOCOL *HiiString;
260
261 Lang = NULL;
262 StringBuffer = NULL;
263
264 //
265 // Init OpCode Handle and Allocate space for creation of UpdateData Buffer
266 //
267 OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
268 ASSERT (OptionsOpCodeHandle != NULL);
269
270 GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL);
271
272 //
273 // Get Support language list from variable.
274 //
275 GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&gLanguageString, NULL);
276 if (gLanguageString == NULL) {
277 gLanguageString = AllocateCopyPool (
278 AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),
279 (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)
280 );
281 ASSERT (gLanguageString != NULL);
282 }
283
284 if (gLanguageToken == NULL) {
285 //
286 // Count the language list number.
287 //
288 LangCode = gLanguageString;
289 Lang = AllocatePool (AsciiStrSize (gLanguageString));
290 ASSERT (Lang != NULL);
291
292 OptionCount = 0;
293 while (*LangCode != 0) {
294 GetNextLanguage (&LangCode, Lang);
295 OptionCount ++;
296 }
297
298 //
299 // Allocate extra 1 as the end tag.
300 //
301 gLanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID));
302 ASSERT (gLanguageToken != NULL);
303
304 Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
305 ASSERT_EFI_ERROR (Status);
306
307 LangCode = gLanguageString;
308 OptionCount = 0;
309 while (*LangCode != 0) {
310 GetNextLanguage (&LangCode, Lang);
311
312 StringSize = 0;
313 Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
314 if (Status == EFI_BUFFER_TOO_SMALL) {
315 StringBuffer = AllocateZeroPool (StringSize);
316 ASSERT (StringBuffer != NULL);
317 Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
318 ASSERT_EFI_ERROR (Status);
319 }
320
321 if (EFI_ERROR (Status)) {
322 StringBuffer = AllocatePool (AsciiStrSize (Lang) * sizeof (CHAR16));
323 ASSERT (StringBuffer != NULL);
324 AsciiStrToUnicodeStr (Lang, StringBuffer);
325 }
326
327 ASSERT (StringBuffer != NULL);
328 gLanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);
329 FreePool (StringBuffer);
330
331 OptionCount++;
332 }
333 }
334
335 ASSERT (gLanguageToken != NULL);
336 LangCode = gLanguageString;
337 OptionCount = 0;
338 if (Lang == NULL) {
339 Lang = AllocatePool (AsciiStrSize (gLanguageString));
340 ASSERT (Lang != NULL);
341 }
342 while (*LangCode != 0) {
343 GetNextLanguage (&LangCode, Lang);
344
345 if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) {
346 HiiCreateOneOfOptionOpCode (
347 OptionsOpCodeHandle,
348 gLanguageToken[OptionCount],
349 EFI_IFR_OPTION_DEFAULT,
350 EFI_IFR_NUMERIC_SIZE_1,
351 (UINT8) OptionCount
352 );
353 } else {
354 HiiCreateOneOfOptionOpCode (
355 OptionsOpCodeHandle,
356 gLanguageToken[OptionCount],
357 0,
358 EFI_IFR_NUMERIC_SIZE_1,
359 (UINT8) OptionCount
360 );
361 }
362
363 OptionCount++;
364 }
365
366 if (CurrentLang != NULL) {
367 FreePool (CurrentLang);
368 }
369 FreePool (Lang);
370
371 HiiCreateOneOfOpCode (
372 StartOpCodeHandle,
373 FRONT_PAGE_KEY_LANGUAGE,
374 0,
375 0,
376 STRING_TOKEN (STR_LANGUAGE_SELECT),
377 STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),
378 EFI_IFR_FLAG_CALLBACK,
379 EFI_IFR_NUMERIC_SIZE_1,
380 OptionsOpCodeHandle,
381 NULL
382 );
383 }
384
385 /**
386 Create continue menu in the front page.
387
388 @param[in] HiiHandle The hii handle for the Uiapp driver.
389 @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
390
391 **/
392 VOID
393 UiCreateContinueMenu (
394 IN EFI_HII_HANDLE HiiHandle,
395 IN VOID *StartOpCodeHandle
396 )
397 {
398 HiiCreateActionOpCode (
399 StartOpCodeHandle,
400 FRONT_PAGE_KEY_CONTINUE,
401 STRING_TOKEN (STR_CONTINUE_PROMPT),
402 STRING_TOKEN (STR_CONTINUE_PROMPT),
403 EFI_IFR_FLAG_CALLBACK,
404 0
405 );
406 }
407
408 /**
409 Create empty line menu in the front page.
410
411 @param HiiHandle The hii handle for the Uiapp driver.
412 @param StartOpCodeHandle The opcode handle to save the new opcode.
413
414 **/
415 VOID
416 UiCreateEmptyLine (
417 IN EFI_HII_HANDLE HiiHandle,
418 IN VOID *StartOpCodeHandle
419 )
420 {
421 HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_NULL_STRING), 0, 0, 0);
422 }
423
424 /**
425 Create Reset menu in the front page.
426
427 @param[in] HiiHandle The hii handle for the Uiapp driver.
428 @param[in] StartOpCodeHandle The opcode handle to save the new opcode.
429
430 **/
431 VOID
432 UiCreateResetMenu (
433 IN EFI_HII_HANDLE HiiHandle,
434 IN VOID *StartOpCodeHandle
435 )
436 {
437 HiiCreateActionOpCode (
438 StartOpCodeHandle,
439 FRONT_PAGE_KEY_RESET,
440 STRING_TOKEN (STR_RESET_STRING),
441 STRING_TOKEN (STR_RESET_STRING),
442 EFI_IFR_FLAG_CALLBACK,
443 0
444 );
445 }
446
447 /**
448 Extract device path for given HII handle and class guid.
449
450 @param Handle The HII handle.
451
452 @retval NULL Fail to get the device path string.
453 @return PathString Get the device path string.
454
455 **/
456 CHAR16 *
457 ExtractDevicePathFromHiiHandle (
458 IN EFI_HII_HANDLE Handle
459 )
460 {
461 EFI_STATUS Status;
462 EFI_HANDLE DriverHandle;
463
464 ASSERT (Handle != NULL);
465
466 if (Handle == NULL) {
467 return NULL;
468 }
469
470 Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
471 if (EFI_ERROR (Status)) {
472 return NULL;
473 }
474
475 return ConvertDevicePathToText(DevicePathFromHandle (DriverHandle), FALSE, FALSE);
476 }
477
478 /**
479 Check whether this driver need to be shown in the front page.
480
481 @param HiiHandle The hii handle for the driver.
482 @param Guid The special guid for the driver which is the target.
483 @param PromptId Return the prompt string id.
484 @param HelpId Return the help string id.
485 @param FormsetGuid Return the formset guid info.
486
487 @retval EFI_SUCCESS Search the driver success
488
489 **/
490 BOOLEAN
491 RequiredDriver (
492 IN EFI_HII_HANDLE HiiHandle,
493 IN EFI_GUID *Guid,
494 OUT EFI_STRING_ID *PromptId,
495 OUT EFI_STRING_ID *HelpId,
496 OUT VOID *FormsetGuid
497 )
498 {
499 EFI_STATUS Status;
500 UINT8 ClassGuidNum;
501 EFI_GUID *ClassGuid;
502 EFI_IFR_FORM_SET *Buffer;
503 UINTN BufferSize;
504 UINT8 *Ptr;
505 UINTN TempSize;
506 BOOLEAN RetVal;
507
508 Status = HiiGetFormSetFromHiiHandle(HiiHandle, &Buffer,&BufferSize);
509 if (EFI_ERROR (Status)) {
510 return FALSE;
511 }
512
513 RetVal = FALSE;
514 TempSize = 0;
515 Ptr = (UINT8 *) Buffer;
516 while(TempSize < BufferSize) {
517 TempSize += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
518
519 if (((EFI_IFR_OP_HEADER *) Ptr)->Length <= OFFSET_OF (EFI_IFR_FORM_SET, Flags)){
520 Ptr += ((EFI_IFR_OP_HEADER *) Ptr)->Length;
521 continue;
522 }
523
524 ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *)Ptr)->Flags & 0x3);
525 ClassGuid = (EFI_GUID *) (VOID *)(Ptr + sizeof (EFI_IFR_FORM_SET));
526 while (ClassGuidNum-- > 0) {
527 if (!CompareGuid (Guid, ClassGuid)){
528 ClassGuid ++;
529 continue;
530 }
531
532 *PromptId = ((EFI_IFR_FORM_SET *)Ptr)->FormSetTitle;
533 *HelpId = ((EFI_IFR_FORM_SET *)Ptr)->Help;
534 CopyMem (FormsetGuid, &((EFI_IFR_FORM_SET *) Ptr)->Guid, sizeof (EFI_GUID));
535 RetVal = TRUE;
536 }
537 }
538
539 FreePool (Buffer);
540
541 return RetVal;
542 }
543
544 /**
545 Search the drivers in the system which need to show in the front page
546 and insert the menu to the front page.
547
548 @param HiiHandle The hii handle for the Uiapp driver.
549 @param ClassGuid The class guid for the driver which is the target.
550 @param StartOpCodeHandle The opcode handle to save the new opcode.
551 @param SpecialHandler The pointer to the specail handler function, if any.
552
553 @retval EFI_SUCCESS Search the driver success
554
555 **/
556 EFI_STATUS
557 UiListThirdPartyDrivers (
558 IN EFI_HII_HANDLE HiiHandle,
559 IN EFI_GUID *ClassGuid,
560 IN DRIVER_SPECIAL_HANDLER SpecialHandlerFn,
561 IN VOID *StartOpCodeHandle
562 )
563 {
564 UINTN Index;
565 EFI_STRING String;
566 EFI_STRING_ID Token;
567 EFI_STRING_ID TokenHelp;
568 EFI_HII_HANDLE *HiiHandles;
569 CHAR16 *DevicePathStr;
570 UINTN Count;
571 UINTN CurrentSize;
572 UI_HII_DRIVER_INSTANCE *DriverListPtr;
573 EFI_STRING NewName;
574 BOOLEAN EmptyLineAfter;
575
576 if (gHiiDriverList != NULL) {
577 FreePool (gHiiDriverList);
578 }
579
580 HiiHandles = HiiGetHiiHandles (NULL);
581 ASSERT (HiiHandles != NULL);
582
583 gHiiDriverList = AllocateZeroPool (UI_HII_DRIVER_LIST_SIZE * sizeof (UI_HII_DRIVER_INSTANCE));
584 ASSERT (gHiiDriverList != NULL);
585 DriverListPtr = gHiiDriverList;
586 CurrentSize = UI_HII_DRIVER_LIST_SIZE;
587
588 for (Index = 0, Count = 0; HiiHandles[Index] != NULL; Index++) {
589 if (!RequiredDriver (HiiHandles[Index], ClassGuid, &Token, &TokenHelp, &gHiiDriverList[Count].FormSetGuid)) {
590 continue;
591 }
592
593 String = HiiGetString (HiiHandles[Index], Token, NULL);
594 if (String == NULL) {
595 String = HiiGetString (gHiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
596 ASSERT (String != NULL);
597 } else if (SpecialHandlerFn != NULL) {
598 //
599 // Check whether need to rename the driver name.
600 //
601 EmptyLineAfter = FALSE;
602 if (SpecialHandlerFn (String, &NewName, &EmptyLineAfter)) {
603 FreePool (String);
604 String = NewName;
605 DriverListPtr[Count].EmptyLineAfter = EmptyLineAfter;
606 }
607 }
608 DriverListPtr[Count].PromptId = HiiSetString (HiiHandle, 0, String, NULL);
609 FreePool (String);
610
611 String = HiiGetString (HiiHandles[Index], TokenHelp, NULL);
612 if (String == NULL) {
613 String = HiiGetString (gHiiHandle, STRING_TOKEN (STR_MISSING_STRING), NULL);
614 ASSERT (String != NULL);
615 }
616 DriverListPtr[Count].HelpId = HiiSetString (HiiHandle, 0, String, NULL);
617 FreePool (String);
618
619 DevicePathStr = ExtractDevicePathFromHiiHandle(HiiHandles[Index]);
620 if (DevicePathStr != NULL){
621 DriverListPtr[Count].DevicePathId = HiiSetString (HiiHandle, 0, DevicePathStr, NULL);
622 FreePool (DevicePathStr);
623 } else {
624 DriverListPtr[Count].DevicePathId = 0;
625 }
626
627 Count++;
628 if (Count >= CurrentSize) {
629 DriverListPtr = AllocateCopyPool ((Count + UI_HII_DRIVER_LIST_SIZE) * sizeof (UI_HII_DRIVER_INSTANCE), gHiiDriverList);
630 ASSERT (DriverListPtr != NULL);
631 FreePool (gHiiDriverList);
632 gHiiDriverList = DriverListPtr;
633 CurrentSize += UI_HII_DRIVER_LIST_SIZE;
634 }
635 }
636
637 FreePool (HiiHandles);
638
639 Index = 0;
640 while (gHiiDriverList[Index].PromptId != 0) {
641 HiiCreateGotoExOpCode (
642 StartOpCodeHandle,
643 0,
644 gHiiDriverList[Index].PromptId,
645 gHiiDriverList[Index].HelpId,
646 0,
647 0,
648 0,
649 &gHiiDriverList[Index].FormSetGuid,
650 gHiiDriverList[Index].DevicePathId
651 );
652
653 if (gHiiDriverList[Index].EmptyLineAfter) {
654 UiCreateEmptyLine (HiiHandle, StartOpCodeHandle);
655 }
656
657 Index ++;
658 }
659
660 return EFI_SUCCESS;
661 }