Update HiiConfigAccess.ExtractConfig interface to support NULL request string and...
[efi/edk2/.git] / edk2 / EdkCompatibilityPkg / Compatibility / FrameworkHiiOnUefiHiiThunk / ConfigAccess.c
1 /** @file\r
2   This file implements functions related to Config Access Protocols installed by\r
3   by HII Thunk Modules. These Config access Protocols are used to thunk UEFI Config \r
4   Access Callback to Framework HII Callback and EFI Variable Set/Get operations.\r
5   \r
6 Copyright (c) 2008 - 2010, Intel Corporation\r
7 All rights reserved. This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution.  The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php\r
11 \r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14 \r
15 **/\r
16 \r
17 #include "HiiDatabase.h"\r
18 #include "UefiIfrParser.h"\r
19 \r
20 BOOLEAN            mHiiPackageListUpdated = FALSE;\r
21 \r
22 HII_VENDOR_DEVICE_PATH  mUefiHiiVendorDevicePath = {\r
23   {\r
24     {\r
25       {\r
26         HARDWARE_DEVICE_PATH,\r
27         HW_VENDOR_DP,\r
28         {\r
29           (UINT8) (sizeof (HII_VENDOR_DEVICE_PATH_NODE)),\r
30           (UINT8) ((sizeof (HII_VENDOR_DEVICE_PATH_NODE)) >> 8)\r
31         }\r
32       },\r
33       EFI_CALLER_ID_GUID\r
34     },\r
35     0,\r
36     0\r
37   },\r
38   {\r
39     END_DEVICE_PATH_TYPE,\r
40     END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
41     { \r
42       (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),\r
43       (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)\r
44     }\r
45   }\r
46 };\r
47 \r
48 CONFIG_ACCESS_PRIVATE gConfigAccessPrivateTempate = {\r
49   CONFIG_ACCESS_PRIVATE_SIGNATURE,\r
50   {\r
51     ThunkExtractConfig,\r
52     ThunkRouteConfig,\r
53     ThunkCallback\r
54   }, //ConfigAccessProtocol\r
55   NULL, //FormCallbackProtocol\r
56   NULL \r
57 };\r
58 \r
59 /**\r
60   Get the first EFI_IFR_VARSTORE from the FormSet. \r
61     \r
62   @param FormSet                  The Form Set.\r
63    \r
64   @retval FORMSET_STORAGE *       Return the first EFI_IFR_VARSTORE.\r
65   @retval NULL                    If the Form Set does not have EFI_IFR_VARSTORE.\r
66 **/\r
67 FORMSET_STORAGE *\r
68 GetFirstStorageOfFormSet (\r
69   IN CONST FORM_BROWSER_FORMSET * FormSet\r
70   ) \r
71 {\r
72   LIST_ENTRY             *StorageList;\r
73   FORMSET_STORAGE        *Storage;\r
74 \r
75   StorageList = GetFirstNode (&FormSet->StorageListHead);\r
76 \r
77   if (!IsNull (&FormSet->StorageListHead, StorageList)) {\r
78     Storage = FORMSET_STORAGE_FROM_LINK (StorageList);\r
79     return Storage;\r
80   }\r
81   \r
82   return NULL;\r
83 }\r
84 \r
85 /**\r
86   Get the FORM_BROWSER_STATEMENT that matches the Question's value.\r
87     \r
88   @param FormSet                  The Form Set.\r
89   @param QuestionId               QuestionId\r
90    \r
91   @retval FORM_BROWSER_STATEMENT*   FORM_BROWSER_STATEMENT that match Question's value.\r
92   @retval NULL                      If the Form Set does not have EFI_IFR_VARSTORE.\r
93 **/\r
94 FORM_BROWSER_STATEMENT *\r
95 GetStorageFromQuestionId (\r
96   IN CONST FORM_BROWSER_FORMSET * FormSet,\r
97   IN       EFI_QUESTION_ID        QuestionId\r
98   )\r
99 {\r
100   LIST_ENTRY             *FormList;\r
101   LIST_ENTRY             *StatementList;\r
102   FORM_BROWSER_FORM      *Form;\r
103   FORM_BROWSER_STATEMENT *Statement;\r
104 \r
105   FormList = GetFirstNode (&FormSet->FormListHead);\r
106 \r
107   while (!IsNull (&FormSet->FormListHead, FormList)) {\r
108     Form = FORM_BROWSER_FORM_FROM_LINK (FormList);\r
109 \r
110     StatementList = GetFirstNode (&Form->StatementListHead);\r
111 \r
112     while (!IsNull (&Form->StatementListHead, StatementList)) {\r
113       Statement = FORM_BROWSER_STATEMENT_FROM_LINK (StatementList);\r
114       if ((QuestionId == Statement->QuestionId) && (Statement->Storage != NULL)) {\r
115         //\r
116         // UEFI Question ID is unique in a FormSet.\r
117         //\r
118         ASSERT (Statement->Storage->Type == EFI_HII_VARSTORE_BUFFER);\r
119         return Statement;\r
120       }\r
121       StatementList = GetNextNode (&Form->StatementListHead, StatementList);\r
122     }\r
123 \r
124     FormList = GetNextNode (&FormSet->FormListHead, FormList);\r
125   }\r
126   \r
127   return NULL;\r
128 }\r
129 \r
130 /**\r
131   Get the EFI_IFR_VARSTORE based the <ConfigHdr> string in a <ConfigRequest>\r
132   or a <ConfigResp> string.\r
133     \r
134   @param FormSet                  The Form Set.\r
135   @param ConfigString             The Configuration String which is defined by UEFI HII.\r
136    \r
137   @retval FORMSET_STORAGE *       The EFI_IFR_VARSTORE where the Question's value is stored.\r
138   @retval NULL                    If the Form Set does not have EFI_IFR_VARSTORE with such ID.\r
139 **/\r
140 FORMSET_STORAGE *\r
141 GetStorageFromConfigString (\r
142   IN CONST FORM_BROWSER_FORMSET *FormSet,\r
143   IN  CONST EFI_STRING          ConfigString\r
144   )\r
145 {\r
146   LIST_ENTRY             *StorageList;\r
147   FORMSET_STORAGE        *Storage;\r
148   CHAR16                 *Name;\r
149 \r
150   if (ConfigString == NULL) {\r
151     return NULL;\r
152   }\r
153 \r
154   StorageList = GetFirstNode (&FormSet->StorageListHead);\r
155 \r
156   while (!IsNull (&FormSet->StorageListHead, StorageList)) {\r
157     Storage = FORMSET_STORAGE_FROM_LINK (StorageList);\r
158 \r
159     if ((Storage->VarStoreId == FormSet->DefaultVarStoreId) && (FormSet->OriginalDefaultVarStoreName != NULL)) {\r
160       Name = FormSet->OriginalDefaultVarStoreName;\r
161     } else {\r
162       Name = Storage->Name;\r
163     }\r
164     \r
165     if (HiiIsConfigHdrMatch (ConfigString, &Storage->Guid, Name)) {\r
166       return Storage;\r
167     }\r
168 \r
169     StorageList = GetNextNode (&FormSet->StorageListHead, StorageList);\r
170   }\r
171 \r
172   return NULL;\r
173 }\r
174 \r
175 /**\r
176   This function installs a EFI_CONFIG_ACCESS_PROTOCOL instance for a form package registered\r
177   by a module using Framework HII Protocol Interfaces.\r
178 \r
179   UEFI HII require EFI_HII_CONFIG_ACCESS_PROTOCOL to be installed on a EFI_HANDLE, so\r
180   that Setup Utility can load the Buffer Storage using this protocol.\r
181    \r
182   @param Packages             The Package List.\r
183   @param ThunkContext         The Thunk Context.\r
184    \r
185   @retval  EFI_SUCCESS        The Config Access Protocol is installed successfully.\r
186   @retval  EFI_OUT_RESOURCE   There is not enough memory.\r
187    \r
188 **/\r
189 EFI_STATUS\r
190 InstallDefaultConfigAccessProtocol (\r
191   IN  CONST EFI_HII_PACKAGES                    *Packages,\r
192   IN  OUT   HII_THUNK_CONTEXT                   *ThunkContext\r
193   )\r
194 {\r
195   EFI_STATUS                                  Status;\r
196   CONFIG_ACCESS_PRIVATE                       *ConfigAccessInstance;\r
197   HII_VENDOR_DEVICE_PATH                      *HiiVendorPath;\r
198 \r
199   ASSERT (ThunkContext->IfrPackageCount != 0);\r
200 \r
201   ConfigAccessInstance = AllocateCopyPool (\r
202                            sizeof (CONFIG_ACCESS_PRIVATE), \r
203                            &gConfigAccessPrivateTempate\r
204                            );\r
205   ASSERT (ConfigAccessInstance != NULL);\r
206 \r
207   //\r
208   // Use memory address as unique ID to distinguish from different device paths\r
209   // This function may be called multi times by the framework HII driver.\r
210   //\r
211   HiiVendorPath = AllocateCopyPool (\r
212                            sizeof (HII_VENDOR_DEVICE_PATH), \r
213                            &mUefiHiiVendorDevicePath\r
214                            );\r
215   ASSERT (HiiVendorPath != NULL);\r
216 \r
217   HiiVendorPath->Node.UniqueId = (UINT64) ((UINTN) HiiVendorPath);\r
218 \r
219   Status = gBS->InstallMultipleProtocolInterfaces (\r
220           &ThunkContext->UefiHiiDriverHandle,\r
221           &gEfiDevicePathProtocolGuid,          \r
222           HiiVendorPath,\r
223           &gEfiHiiConfigAccessProtocolGuid,\r
224           &ConfigAccessInstance->ConfigAccessProtocol,\r
225           NULL\r
226           );\r
227   ASSERT_EFI_ERROR (Status);\r
228   \r
229   ConfigAccessInstance->ThunkContext = ThunkContext;\r
230   \r
231   return EFI_SUCCESS;\r
232 }\r
233 \r
234 /**\r
235   This function un-installs the EFI_CONFIG_ACCESS_PROTOCOL instance for a form package registered\r
236   by a module using Framework HII Protocol Interfaces.\r
237 \r
238   ASSERT if no Config Access is found for such pakcage list or failed to uninstall the protocol.\r
239 \r
240   @param ThunkContext         The Thunk Context.\r
241    \r
242 **/\r
243 VOID\r
244 UninstallDefaultConfigAccessProtocol (\r
245   IN  HII_THUNK_CONTEXT                   *ThunkContext\r
246   )\r
247 {\r
248   EFI_STATUS                      Status;\r
249   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
250   HII_VENDOR_DEVICE_PATH          *HiiVendorPath;\r
251 \r
252   Status = gBS->HandleProtocol (\r
253                   ThunkContext->UefiHiiDriverHandle,\r
254                   &gEfiHiiConfigAccessProtocolGuid,\r
255                   (VOID **) &ConfigAccess\r
256                   );\r
257   ASSERT_EFI_ERROR (Status);\r
258 \r
259   Status = gBS->HandleProtocol (\r
260                   ThunkContext->UefiHiiDriverHandle,\r
261                   &gEfiDevicePathProtocolGuid,\r
262                   (VOID **) &HiiVendorPath\r
263                   );\r
264   ASSERT_EFI_ERROR (Status);\r
265 \r
266   Status = gBS->UninstallMultipleProtocolInterfaces (\r
267                   ThunkContext->UefiHiiDriverHandle,\r
268                   &gEfiDevicePathProtocolGuid,\r
269                   HiiVendorPath,\r
270                   &gEfiHiiConfigAccessProtocolGuid,\r
271                   ConfigAccess,\r
272                   NULL\r
273                   );\r
274   ASSERT_EFI_ERROR (Status);\r
275 \r
276 }\r
277   \r
278 \r
279 /**\r
280    Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to EFI_FORM_CALLBACK_PROTOCOL.NvRead.\r
281    \r
282    @param BufferStorage         The key with all attributes needed to call EFI_FORM_CALLBACK_PROTOCOL.NvRead.\r
283    @param FwFormCallBack    The EFI_FORM_CALLBACK_PROTOCOL registered by Framework HII module.\r
284    @param Data                     The data read.\r
285    @param DataSize                 The size of data.\r
286    \r
287    @retval EFI_STATUS              The status returned by the EFI_FORM_CALLBACK_PROTOCOL.NvWrite.\r
288    @retval EFI_INVALID_PARAMETER   If the EFI_FORM_CALLBACK_PROTOCOL.NvRead return the size information of the data\r
289                                    does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r
290  **/\r
291 EFI_STATUS\r
292 CallFormCallBack (\r
293   IN       FORMSET_STORAGE                            *BufferStorage,\r
294   IN       EFI_FORM_CALLBACK_PROTOCOL                 *FwFormCallBack,\r
295   OUT      VOID                                       **Data,\r
296   OUT      UINTN                                      *DataSize\r
297   )\r
298 {\r
299   EFI_STATUS          Status;\r
300 \r
301   *DataSize = 0;\r
302   *Data     = NULL;\r
303   \r
304   Status = FwFormCallBack->NvRead (\r
305               FwFormCallBack,  \r
306               BufferStorage->Name,\r
307               &BufferStorage->Guid,\r
308               NULL,\r
309               DataSize,\r
310               *Data\r
311               );\r
312   if (Status == EFI_BUFFER_TOO_SMALL) {\r
313     if (BufferStorage->Size != *DataSize) {\r
314       ASSERT (FALSE);\r
315       return EFI_INVALID_PARAMETER;\r
316     }\r
317 \r
318     *Data = AllocateZeroPool (*DataSize);\r
319     if (*Data == NULL) {\r
320       return EFI_OUT_OF_RESOURCES;\r
321     }\r
322 \r
323     Status = FwFormCallBack->NvRead (\r
324                   FwFormCallBack,  \r
325                   BufferStorage->Name,\r
326                   &BufferStorage->Guid,\r
327                   NULL,\r
328                   DataSize,\r
329                   *Data\r
330                   );\r
331   }\r
332 \r
333   return Status;\r
334 }\r
335 \r
336 \r
337 /**\r
338    Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to UEFI Variable Get Service.\r
339    \r
340    @param BufferStorage        The key with all attributes needed to call a UEFI Variable Get Service.\r
341    @param Data                    The data read.\r
342    @param DataSize                The size of data.\r
343 \r
344    If the UEFI Variable Get Service return the size information of the data\r
345    does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r
346    then ASSERT.\r
347                                                         \r
348    @retval EFI_STATUS              The status returned by the UEFI Variable Get Service.\r
349    @retval EFI_INVALID_PARAMETER   If the UEFI Variable Get Service return the size information of the data\r
350                                    does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r
351  **/\r
352 EFI_STATUS\r
353 GetUefiVariable (\r
354   IN       FORMSET_STORAGE                            *BufferStorage,\r
355   OUT      VOID                                       **Data,\r
356   OUT      UINTN                                      *DataSize\r
357   )\r
358 {\r
359   EFI_STATUS          Status;\r
360 \r
361   *DataSize = 0;\r
362   *Data = NULL;\r
363   Status = gRT->GetVariable (\r
364               BufferStorage->Name,\r
365               &BufferStorage->Guid,\r
366               NULL,\r
367               DataSize,\r
368               *Data\r
369               );\r
370   if (Status == EFI_BUFFER_TOO_SMALL) {\r
371 \r
372     if (BufferStorage->Size != *DataSize) {\r
373       ASSERT (FALSE);\r
374       return EFI_INVALID_PARAMETER;\r
375     }\r
376 \r
377     *Data = AllocateZeroPool (*DataSize);\r
378     if (*Data == NULL) {\r
379       return EFI_OUT_OF_RESOURCES;\r
380     }\r
381 \r
382     Status = gRT->GetVariable (\r
383                 BufferStorage->Name,\r
384                 &BufferStorage->Guid,\r
385                 NULL,\r
386                 DataSize,\r
387                 *Data\r
388                 );\r
389   }\r
390 \r
391   return Status;\r
392 }\r
393 \r
394 /**\r
395 \r
396   This function implement the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig\r
397   so that data can be read from the data storage such as UEFI Variable or module's\r
398   customized storage exposed by EFI_FRAMEWORK_CALLBACK.\r
399 \r
400    @param This        Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
401    @param Request     A null-terminated Unicode string in <ConfigRequest> format. Note that this\r
402                       includes the routing information as well as the configurable name / value pairs. It is\r
403                       invalid for this string to be in <MultiConfigRequest> format.\r
404 \r
405    @param Progress    On return, points to a character in the Request string. Points to the string's null\r
406                       terminator if request was successful. Points to the most recent '&' before the first\r
407                       failing name / value pair (or the beginning of the string if the failure is in the first\r
408                       name / value pair) if the request was not successful\r
409    @param Results     A null-terminated Unicode string in <ConfigAltResp> format which has all\r
410                       values filled in for the names in the Request string. String to be allocated by the called\r
411                       function.\r
412    \r
413    @retval EFI_INVALID_PARAMETER   If there is no Buffer Storage for this Config Access instance.\r
414    @retval EFI_SUCCESS             The setting is retrived successfully.\r
415    @retval !EFI_SUCCESS            The error returned by UEFI Get Variable or Framework Form Callback Nvread.\r
416  **/\r
417 EFI_STATUS\r
418 EFIAPI\r
419 ThunkExtractConfig (\r
420   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
421   IN  CONST EFI_STRING                       Request,\r
422   OUT EFI_STRING                             *Progress,\r
423   OUT EFI_STRING                             *Results\r
424   )\r
425 {\r
426   EFI_STATUS                       Status;\r
427   CONFIG_ACCESS_PRIVATE            *ConfigAccess;\r
428   FORMSET_STORAGE                  *BufferStorage;\r
429   VOID                             *Data;\r
430   UINTN                            DataSize;\r
431   FORM_BROWSER_FORMSET             *FormSetContext;\r
432   CHAR16                           *VarStoreName;\r
433   EFI_STRING                       ConfigRequestHdr;\r
434   EFI_STRING                       ConfigRequest;\r
435   UINTN                            Size;\r
436   BOOLEAN                          AllocatedRequest;\r
437   LIST_ENTRY                       *StorageList;\r
438   EFI_STRING                       SingleResult;\r
439   EFI_STRING                       FinalResults;\r
440   EFI_STRING                       StrPointer;\r
441 \r
442   if (Progress == NULL || Results == NULL) {\r
443     return EFI_INVALID_PARAMETER;\r
444   }\r
445   *Progress = Request;\r
446 \r
447   Status         = EFI_SUCCESS;\r
448   Data           = NULL;\r
449   StrPointer     = NULL;\r
450   SingleResult   = NULL;\r
451   FinalResults   = NULL;\r
452   ConfigAccess   = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
453   FormSetContext = ConfigAccess->ThunkContext->FormSet;\r
454   if (IsListEmpty (&FormSetContext->StorageListHead)) {\r
455     //\r
456     // No VarStorage does exist in this form.\r
457     //\r
458     return EFI_NOT_FOUND;\r
459   }\r
460   StorageList    = GetFirstNode (&FormSetContext->StorageListHead);\r
461 \r
462   do {\r
463     if (Request != NULL) {\r
464       BufferStorage = GetStorageFromConfigString (ConfigAccess->ThunkContext->FormSet, Request);\r
465       if (BufferStorage == NULL) {\r
466         return EFI_NOT_FOUND;\r
467       }\r
468     } else {\r
469       if (IsNull (&FormSetContext->StorageListHead, StorageList)) {\r
470         //\r
471         // No Storage to be extracted into the results.\r
472         //\r
473         break;\r
474       }\r
475       BufferStorage = FORMSET_STORAGE_FROM_LINK (StorageList);\r
476       StorageList = GetNextNode (&FormSetContext->StorageListHead, StorageList);\r
477     }\r
478   \r
479     VarStoreName     = NULL;\r
480     ConfigRequestHdr = NULL;\r
481     ConfigRequest    = NULL;\r
482     Size             = 0;\r
483     AllocatedRequest = FALSE;\r
484 \r
485     if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
486       //\r
487       // NvMapOverride is not used. Get the Storage data from EFI Variable or Framework Form Callback.\r
488       //\r
489       if (ConfigAccess->FormCallbackProtocol == NULL ||\r
490           ConfigAccess->FormCallbackProtocol->NvRead == NULL) {\r
491         Status = GetUefiVariable (\r
492                    BufferStorage,\r
493                    &Data,\r
494                    &DataSize\r
495                    );\r
496       } else {\r
497         Status = CallFormCallBack (\r
498                    BufferStorage,\r
499                    ConfigAccess->FormCallbackProtocol,\r
500                     &Data,\r
501                     &DataSize\r
502                    );\r
503       }\r
504     } else {\r
505       //\r
506       // Use the NvMapOverride.\r
507       //\r
508       DataSize = BufferStorage->Size;\r
509       Data = AllocateCopyPool (DataSize, ConfigAccess->ThunkContext->NvMapOverride);\r
510       \r
511       if (Data != NULL) {\r
512         Status = EFI_SUCCESS;\r
513       } else {\r
514         Status = EFI_OUT_OF_RESOURCES;\r
515       }\r
516     }\r
517     \r
518     if (!EFI_ERROR (Status)) {\r
519       ConfigRequest = Request;\r
520       if (Request == NULL || (StrStr (Request, L"OFFSET") == NULL)) {\r
521         //\r
522         // Request is without any request element, construct full request string.\r
523         //\r
524 \r
525         if ((BufferStorage->VarStoreId == FormSetContext->DefaultVarStoreId) && (FormSetContext->OriginalDefaultVarStoreName != NULL)) {\r
526           VarStoreName = FormSetContext->OriginalDefaultVarStoreName;\r
527         } else {\r
528           VarStoreName = BufferStorage->Name;\r
529         }\r
530 \r
531         //\r
532         // First Set ConfigRequestHdr string.\r
533         //\r
534         ConfigRequestHdr = HiiConstructConfigHdr (&BufferStorage->Guid, VarStoreName, ConfigAccess->ThunkContext->UefiHiiDriverHandle);\r
535         ASSERT (ConfigRequestHdr != NULL);\r
536 \r
537         //\r
538         // Allocate and fill a buffer large enough to hold the <ConfigHdr> template \r
539         // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator\r
540         //\r
541         Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
542         ConfigRequest = AllocateZeroPool (Size);\r
543         ASSERT (ConfigRequest != NULL);\r
544         AllocatedRequest = TRUE;\r
545         UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)DataSize);\r
546         FreePool (ConfigRequestHdr);\r
547       }\r
548       Status = mHiiConfigRoutingProtocol->BlockToConfig (\r
549                                               mHiiConfigRoutingProtocol,\r
550                                               ConfigRequest,\r
551                                               Data,\r
552                                               DataSize,\r
553                                               &SingleResult,\r
554                                               Progress\r
555                                               );\r
556       //\r
557       // Free the allocated config request string.\r
558       //\r
559       if (AllocatedRequest) {\r
560         FreePool (ConfigRequest);\r
561         ConfigRequest = NULL;\r
562       }\r
563     }\r
564     //\r
565     // Free the allocated Data\r
566     //\r
567     if (Data != NULL) {\r
568       FreePool (Data);\r
569     }\r
570     //\r
571     // Directly return when meet with error\r
572     //\r
573     if (EFI_ERROR (Status)) {\r
574       break;\r
575     }\r
576     //\r
577     // Merge result into the final results.\r
578     //\r
579     if (FinalResults == NULL) {\r
580       FinalResults = SingleResult;\r
581       SingleResult = NULL;\r
582     } else {\r
583       Size = StrLen (FinalResults);\r
584       Size = Size + 1;\r
585       Size = Size + StrLen (SingleResult) + 1;\r
586       StrPointer = AllocateZeroPool (Size * sizeof (CHAR16));\r
587       ASSERT (StrPointer != NULL);\r
588       StrCpy (StrPointer, FinalResults);\r
589       FreePool (FinalResults);\r
590       FinalResults = StrPointer;\r
591       StrPointer  = StrPointer + StrLen (StrPointer);\r
592       *StrPointer = L'&';\r
593       StrCpy (StrPointer + 1, SingleResult);\r
594       FreePool (SingleResult);\r
595     }\r
596   } while (Request == NULL);\r
597 \r
598   if (!EFI_ERROR (Status)) {\r
599     *Results = FinalResults;\r
600   } else {\r
601     if (FinalResults != NULL) {\r
602       FreePool (FinalResults);\r
603     }\r
604   }\r
605   //\r
606   // Set Progress string to the original request string.\r
607   //\r
608   if (Request == NULL) {\r
609     *Progress = NULL;\r
610   } else if (StrStr (Request, L"OFFSET") == NULL) {\r
611     *Progress = Request + StrLen (Request);\r
612   }\r
613 \r
614   return Status;\r
615 }\r
616 \r
617 /**\r
618   This function implement the EFI_HII_CONFIG_ACCESS_PROTOCOL.RouteConfig\r
619   so that data can be written to the data storage such as UEFI Variable or module's\r
620   customized storage exposed by EFI_FRAMEWORK_CALLBACK.\r
621    \r
622    @param This             Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
623    @param Configuration    A null-terminated Unicode string in <ConfigResp> format.\r
624    @param Progress         A pointer to a string filled in with the offset of the most recent '&' before the first\r
625                            failing name / value pair (or the beginning of the string if the failure is in the first\r
626                            name / value pair) or the terminating NULL if all was successful.\r
627    \r
628    @retval EFI_INVALID_PARAMETER   If there is no Buffer Storage for this Config Access instance.\r
629    @retval EFI_SUCCESS             The setting is saved successfully.\r
630    @retval !EFI_SUCCESS            The error returned by UEFI Set Variable or Framework Form Callback Nvwrite.\r
631 **/   \r
632 EFI_STATUS\r
633 EFIAPI\r
634 ThunkRouteConfig (\r
635   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
636   IN  CONST EFI_STRING                       Configuration,\r
637   OUT EFI_STRING                             *Progress\r
638   )\r
639 {\r
640   EFI_STATUS                                  Status;\r
641   CONFIG_ACCESS_PRIVATE                       *ConfigAccess;\r
642   FORMSET_STORAGE                             *BufferStorage;\r
643   VOID                                        *Data;\r
644   UINTN                                       DataSize;\r
645   UINTN                                       DataSize2;\r
646   BOOLEAN                                     ResetRequired;\r
647   BOOLEAN                                     DataAllocated;\r
648 \r
649   if (Configuration == NULL) {\r
650     return EFI_INVALID_PARAMETER;\r
651   }\r
652 \r
653   Data = NULL;\r
654   ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
655 \r
656   BufferStorage = GetStorageFromConfigString (ConfigAccess->ThunkContext->FormSet, Configuration);\r
657 \r
658   if (BufferStorage == NULL) {\r
659     *Progress = Configuration;\r
660     return EFI_NOT_FOUND;\r
661   }\r
662 \r
663   DataSize2     = BufferStorage->Size;\r
664   if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
665     DataAllocated = TRUE;\r
666     if (ConfigAccess->FormCallbackProtocol == NULL ||\r
667         ConfigAccess->FormCallbackProtocol->NvRead == NULL) {\r
668       Status = GetUefiVariable (\r
669                  BufferStorage,\r
670                  &Data,\r
671                  &DataSize\r
672                  );\r
673     } else {\r
674       Status = CallFormCallBack (\r
675                  BufferStorage,\r
676                  ConfigAccess->FormCallbackProtocol,\r
677                   &Data,\r
678                   &DataSize\r
679                  );\r
680     }\r
681   } else {\r
682     //\r
683     // ConfigToBlock will convert the Config String and update the NvMapOverride accordingly.\r
684     //\r
685     Status = EFI_SUCCESS;\r
686     Data = ConfigAccess->ThunkContext->NvMapOverride;\r
687     DataSize      = DataSize2;\r
688     DataAllocated = FALSE;\r
689   }  \r
690   if (EFI_ERROR (Status) || (DataSize2 != DataSize)) {\r
691     if (Data == NULL) {\r
692       Data = AllocateZeroPool (DataSize2);\r
693     }\r
694   }\r
695 \r
696   DataSize = DataSize2;\r
697   Status = mHiiConfigRoutingProtocol->ConfigToBlock (\r
698                                           mHiiConfigRoutingProtocol,\r
699                                           Configuration,\r
700                                           Data,\r
701                                           &DataSize,\r
702                                           Progress\r
703                                           );\r
704   if (EFI_ERROR (Status)) {\r
705     goto Done;\r
706   }\r
707   \r
708   if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
709     if (ConfigAccess->FormCallbackProtocol == NULL ||\r
710         ConfigAccess->FormCallbackProtocol->NvWrite == NULL) {\r
711       Status = gRT->SetVariable (\r
712                     BufferStorage->Name,\r
713                     &BufferStorage->Guid,\r
714                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
715                     DataSize2,\r
716                     Data\r
717                     );\r
718     } else {\r
719       Status = ConfigAccess->FormCallbackProtocol->NvWrite (\r
720                     ConfigAccess->FormCallbackProtocol,  \r
721                     BufferStorage->Name,\r
722                     &BufferStorage->Guid,\r
723                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
724                     DataSize2,\r
725                     Data,\r
726                     &ResetRequired\r
727                     );\r
728     }\r
729   }\r
730 \r
731 Done: \r
732   if (DataAllocated && (Data != NULL)) {\r
733     FreePool (Data);\r
734   }\r
735   \r
736   return Status;\r
737 }\r
738 \r
739 /**\r
740   Build the EFI_IFR_DATA_ARRAY which will be used to pass to \r
741   EFI_FORM_CALLBACK_PROTOCOL.Callback. Check definition of EFI_IFR_DATA_ARRAY\r
742   for details.\r
743 \r
744   ASSERT if the Question Type is not EFI_IFR_TYPE_NUM_SIZE_* or EFI_IFR_TYPE_STRING.\r
745   \r
746    @param ConfigAccess     Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
747    @param QuestionId       The Question ID.\r
748    @param Type             The Question Type.\r
749    @param Value            The Question Value.\r
750    @param NvMapAllocated   On output indicates if a buffer is allocated for NvMap.\r
751    \r
752    @return A pointer to EFI_IFR_DATA_ARRAY. The caller must free this buffer allocated.\r
753 **/   \r
754 EFI_IFR_DATA_ARRAY *\r
755 CreateIfrDataArray (\r
756   IN    CONFIG_ACCESS_PRIVATE         *ConfigAccess,\r
757   IN    EFI_QUESTION_ID               QuestionId,\r
758   IN    UINT8                         Type,\r
759   IN    EFI_IFR_TYPE_VALUE            *Value,\r
760   OUT   BOOLEAN                       *NvMapAllocated\r
761   )\r
762 {\r
763   EFI_IFR_DATA_ARRAY                *IfrDataArray;\r
764   EFI_IFR_DATA_ENTRY                *IfrDataEntry;\r
765   UINTN                             BrowserDataSize;\r
766   FORMSET_STORAGE                   *BufferStorage;\r
767   UINTN                             Size;\r
768   EFI_STRING                        String;\r
769   FORM_BROWSER_STATEMENT            *Statement;\r
770 \r
771   *NvMapAllocated = FALSE;\r
772 \r
773   String = NULL;\r
774 \r
775   switch (Type) {\r
776     case EFI_IFR_TYPE_NUM_SIZE_8:\r
777     case EFI_IFR_TYPE_NUM_SIZE_16:\r
778     case EFI_IFR_TYPE_NUM_SIZE_32:\r
779     case EFI_IFR_TYPE_NUM_SIZE_64:\r
780     case EFI_IFR_TYPE_BOOLEAN:\r
781       Size = sizeof (*Value);\r
782       break;\r
783 \r
784     case EFI_IFR_TYPE_STRING:\r
785       if (Value->string == 0) {\r
786         Size = 0;\r
787       } else {\r
788         String = HiiGetString (ConfigAccess->ThunkContext->UefiHiiHandle, Value->string, NULL);\r
789         ASSERT (String != NULL);\r
790 \r
791         Size = StrSize (String);\r
792       }\r
793       break;\r
794 \r
795     case EFI_IFR_TYPE_ACTION:\r
796       Size = 0;\r
797       break;\r
798       \r
799     default:\r
800       ASSERT (FALSE);\r
801       Size = 0;\r
802       break;\r
803   }\r
804 \r
805   IfrDataArray = AllocateZeroPool (sizeof (EFI_IFR_DATA_ARRAY) + sizeof (EFI_IFR_DATA_ENTRY) + Size);\r
806   ASSERT (IfrDataArray != NULL);\r
807   IfrDataArray->EntryCount = 1;\r
808   IfrDataEntry             = (EFI_IFR_DATA_ENTRY *) (IfrDataArray + 1);\r
809 \r
810   Statement = GetStorageFromQuestionId (ConfigAccess->ThunkContext->FormSet, QuestionId);\r
811 \r
812   if (Statement == NULL || Statement->Storage == NULL) {\r
813     //\r
814     // The QuestionId is not associated with a Buffer Storage.\r
815     // Try to get the first Buffer Storage then.\r
816     //\r
817     BufferStorage = GetFirstStorageOfFormSet (ConfigAccess->ThunkContext->FormSet);\r
818   } else {\r
819     BufferStorage        = Statement->Storage;\r
820     IfrDataEntry->OpCode = Statement->Operand;\r
821   }\r
822   \r
823   if (BufferStorage != NULL) {\r
824     BrowserDataSize      = BufferStorage->Size;\r
825     IfrDataEntry->Length = (UINT8) (sizeof (EFI_IFR_DATA_ENTRY) + Size);\r
826 \r
827     if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
828       *NvMapAllocated = TRUE;\r
829       IfrDataArray->NvRamMap = AllocateZeroPool (BrowserDataSize);\r
830     } else {\r
831       *NvMapAllocated = FALSE;\r
832       IfrDataArray->NvRamMap = ConfigAccess->ThunkContext->NvMapOverride;\r
833     }\r
834     \r
835     ASSERT (HiiGetBrowserData (&BufferStorage->Guid, BufferStorage->Name, BrowserDataSize, (UINT8 *) IfrDataArray->NvRamMap));\r
836 \r
837     switch (Type) {\r
838       case EFI_IFR_TYPE_NUM_SIZE_8:\r
839       case EFI_IFR_TYPE_NUM_SIZE_16:\r
840       case EFI_IFR_TYPE_NUM_SIZE_32:\r
841       case EFI_IFR_TYPE_NUM_SIZE_64:\r
842       case EFI_IFR_TYPE_BOOLEAN:\r
843         CopyMem (&IfrDataEntry->Data, &(Value->u8), sizeof (*Value));\r
844         break;\r
845 \r
846       case EFI_IFR_TYPE_STRING:\r
847         if (Size != 0) {\r
848           ASSERT (String != NULL);\r
849           StrCpy ((CHAR16 *) &IfrDataEntry->Data, String);\r
850           FreePool (String);\r
851         }\r
852         break;\r
853 \r
854       case EFI_IFR_TYPE_ACTION:\r
855         break;\r
856 \r
857       default:\r
858         ASSERT (FALSE);\r
859         break;\r
860     }\r
861 \r
862     //\r
863     // Need to fiil in the information for the rest of field for EFI_IFR_DATA_ENTRY.\r
864     // It seems that no implementation is found to use other fields. Leave them uninitialized for now.\r
865     //\r
866     //UINT8   OpCode;           // Likely a string, numeric, or one-of\r
867     //UINT8   Length;           // Length of the EFI_IFR_DATA_ENTRY packet\r
868     //UINT16  Flags;            // Flags settings to determine what behavior is desired from the browser after the callback\r
869     //VOID    *Data;            // The data in the form based on the op-code type - this is not a pointer to the data, the data follows immediately\r
870     // If the OpCode is a OneOf or Numeric type - Data is a UINT16 value\r
871     // If the OpCode is a String type - Data is a CHAR16[x] type\r
872     // If the OpCode is a Checkbox type - Data is a UINT8 value\r
873     // If the OpCode is a NV Access type - Data is a FRAMEWORK_EFI_IFR_NV_DATA structure\r
874   }\r
875 \r
876   return IfrDataArray;\r
877 }\r
878 \r
879 /**\r
880   If a NvMapOverride is passed in to EFI_FORM_BROWSER_PROTOCOL.SendForm, the Form Browser\r
881   needs to be informed when data changed in NvMapOverride. This function will invoke\r
882   SetBrowserData () to set internal data of Form Browser.\r
883 \r
884   @param  ConfigAccess   The Config Access Private Context.\r
885   @param  QuestionId     The Question Id that invokes the callback.\r
886   \r
887 \r
888 **/\r
889 VOID\r
890 SyncBrowserDataForNvMapOverride (\r
891   IN    CONST CONFIG_ACCESS_PRIVATE         *ConfigAccess,\r
892   IN          EFI_QUESTION_ID               QuestionId\r
893   )\r
894 {\r
895   FORMSET_STORAGE   *BufferStorage;\r
896   BOOLEAN           CheckFlag;\r
897   UINTN             BrowserDataSize;\r
898   FORM_BROWSER_STATEMENT *Statement;\r
899 \r
900   if (ConfigAccess->ThunkContext->NvMapOverride != NULL) {\r
901 \r
902     Statement = GetStorageFromQuestionId (ConfigAccess->ThunkContext->FormSet, QuestionId);\r
903 \r
904     if (Statement == NULL || Statement->Storage == NULL) {\r
905       //\r
906       // QuestionId is a statement without Storage.\r
907       // 1) It is a Goto. \r
908       // \r
909       //\r
910       BufferStorage = GetFirstStorageOfFormSet (ConfigAccess->ThunkContext->FormSet);\r
911     } else {\r
912       BufferStorage = Statement->Storage;\r
913     }\r
914 \r
915     //\r
916     // If NvMapOverride is not NULL, this Form must have at least one Buffer Type Variable Storage.\r
917     //\r
918     ASSERT (BufferStorage != NULL);\r
919     \r
920     BrowserDataSize = BufferStorage->Size;\r
921 \r
922     CheckFlag = HiiSetBrowserData (&BufferStorage->Guid, BufferStorage->Name, BrowserDataSize, ConfigAccess->ThunkContext->NvMapOverride, NULL);\r
923     ASSERT (CheckFlag);\r
924   }\r
925 \r
926 }\r
927 \r
928 /**\r
929   Free up resource allocated for a EFI_IFR_DATA_ARRAY by CreateIfrDataArray ().\r
930 \r
931   @param Array              The EFI_IFR_DATA_ARRAY allocated.\r
932   @param NvMapAllocated     If the NvRamMap is allocated for EFI_IFR_DATA_ARRAY.\r
933 \r
934 **/\r
935 VOID\r
936 DestroyIfrDataArray (\r
937   IN  EFI_IFR_DATA_ARRAY           *Array,\r
938   IN  BOOLEAN                      NvMapAllocated\r
939   )\r
940 {\r
941   if (Array != NULL) {\r
942     if (NvMapAllocated) {\r
943       FreePool (Array->NvRamMap);\r
944     }\r
945 \r
946     FreePool (Array);\r
947   }\r
948 }\r
949 \r
950 /**\r
951   Get the ONE_OF_OPTION_MAP_ENTRY for a QuestionId that invokes the \r
952   EFI_FORM_CALLBACK_PROTOCOL.Callback. The information is needed as\r
953   the callback mechanism for EFI_IFR_ONE_OF_OPTION is changed from \r
954   EFI_IFR_ONE_OF_OPTION in Framework IFR. Check EFI_IFR_GUID_OPTIONKEY\r
955   for detailed information.\r
956 \r
957   @param ThunkContext   The Thunk Context.\r
958   @param QuestionId     The Question Id.\r
959   @param Type           The Question Type.\r
960   @param Value          The One Of Option's value.\r
961 \r
962   @return The ONE_OF_OPTION_MAP_ENTRY found.\r
963   @retval NULL If no entry is found.\r
964 **/\r
965 ONE_OF_OPTION_MAP_ENTRY *\r
966 GetOneOfOptionMapEntry (\r
967   IN  HII_THUNK_CONTEXT              *ThunkContext,\r
968   IN  EFI_QUESTION_ID                QuestionId,\r
969   IN  UINT8                          Type,\r
970   IN  EFI_IFR_TYPE_VALUE             *Value\r
971   )\r
972 {\r
973   LIST_ENTRY              *Link;\r
974   LIST_ENTRY              *Link2;\r
975   ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r
976   ONE_OF_OPTION_MAP       *OneOfOptionMap;\r
977   FORM_BROWSER_FORMSET    *FormSet;\r
978 \r
979   FormSet = ThunkContext->FormSet;\r
980 \r
981   Link = GetFirstNode (&FormSet->OneOfOptionMapListHead);\r
982 \r
983   while (!IsNull (&FormSet->OneOfOptionMapListHead, Link)) {\r
984     OneOfOptionMap = ONE_OF_OPTION_MAP_FROM_LINK(Link);\r
985     if (OneOfOptionMap->QuestionId == QuestionId) {\r
986       ASSERT (OneOfOptionMap->ValueType == Type);\r
987 \r
988       Link2 = GetFirstNode (&OneOfOptionMap->OneOfOptionMapEntryListHead);\r
989 \r
990       while (!IsNull (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2)) {\r
991         OneOfOptionMapEntry = ONE_OF_OPTION_MAP_ENTRY_FROM_LINK (Link2);\r
992 \r
993         if (CompareMem (Value, &OneOfOptionMapEntry->Value, sizeof (EFI_IFR_TYPE_VALUE)) == 0) {\r
994           return OneOfOptionMapEntry;\r
995         }\r
996 \r
997         Link2 = GetNextNode (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2);\r
998       }\r
999     }\r
1000 \r
1001     Link = GetNextNode (&FormSet->OneOfOptionMapListHead, Link);\r
1002   }\r
1003 \r
1004 \r
1005   return NULL;\r
1006 }\r
1007 \r
1008 /**\r
1009   Functions which are registered to receive notification of\r
1010   database events have this prototype. The actual event is encoded\r
1011   in NotifyType. The following table describes how PackageType,\r
1012   PackageGuid, Handle, and Package are used for each of the\r
1013   notification types.\r
1014 \r
1015   If any Pakcage List in database is updated, mHiiPackageListUpdated\r
1016   will be set. If mHiiPackageListUpdated is set, Framework ThunkCallback()\r
1017   will force the UEFI Setup Browser to save the uncommitted data. This\r
1018   is needed as Framework's Callback function may dynamically update\r
1019   opcode in a Package List. UEFI Setup Browser will quit itself and reparse\r
1020   the Package List's IFR and display it. UEFI Config Access's implementation\r
1021   is required to save the modified (SetBrowserData or directly save the data\r
1022   to NV storage). But Framework HII Modules is not aware of this rule. Therefore,\r
1023   we will enforce the rule in ThunkCallback (). The side effect of force saving\r
1024   of NV data is the NV flag in browser may not flag a update as data has already\r
1025   been saved to NV storage.\r
1026 \r
1027   @param PackageType  Package type of the notification.\r
1028 \r
1029   @param PackageGuid  If PackageType is\r
1030                       EFI_HII_PACKAGE_TYPE_GUID, then this is\r
1031                       the pointer to the GUID from the Guid\r
1032                       field of EFI_HII_PACKAGE_GUID_HEADER.\r
1033                       Otherwise, it must be NULL.\r
1034 \r
1035   @param Package  Points to the package referred to by the\r
1036                   notification Handle The handle of the package\r
1037                   list which contains the specified package.\r
1038 \r
1039   @param Handle       The HII handle.\r
1040 \r
1041   @param NotifyType   The type of change concerning the\r
1042                       database. See\r
1043                       EFI_HII_DATABASE_NOTIFY_TYPE.\r
1044 \r
1045 **/\r
1046 EFI_STATUS\r
1047 EFIAPI\r
1048 FormUpdateNotify (\r
1049   IN UINT8                              PackageType,\r
1050   IN CONST EFI_GUID                     *PackageGuid,\r
1051   IN CONST EFI_HII_PACKAGE_HEADER       *Package,\r
1052   IN EFI_HII_HANDLE                     Handle,\r
1053   IN EFI_HII_DATABASE_NOTIFY_TYPE       NotifyType\r
1054   )\r
1055 {\r
1056   mHiiPackageListUpdated = TRUE;\r
1057 \r
1058   return EFI_SUCCESS;\r
1059 }\r
1060 \r
1061 /**\r
1062   Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.CallBack to EFI_FORM_CALLBACK_PROTOCOL.Callback. Therefor,\r
1063   the framework HII module willl do no porting and work with a UEFI HII SetupBrowser.\r
1064    \r
1065    @param This                      Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
1066    @param Action                    Specifies the type of action taken by the browser. See EFI_BROWSER_ACTION_x.\r
1067    @param QuestionId                A unique value which is sent to the original exporting driver so that it can identify the\r
1068                                     type of data to expect. The format of the data tends to vary based on the opcode that\r
1069                                     generated the callback.\r
1070    @param Type                      The type of value for the question. See EFI_IFR_TYPE_x in\r
1071                                     EFI_IFR_ONE_OF_OPTION.\r
1072    @param Value                     A pointer to the data being sent to the original exporting driver. The type is specified\r
1073                                     by Type. Type EFI_IFR_TYPE_VALUE is defined in\r
1074                                     EFI_IFR_ONE_OF_OPTION.\r
1075    @param ActionRequest             On return, points to the action requested by the callback function. Type\r
1076                                     EFI_BROWSER_ACTION_REQUEST is specified in SendForm() in the Form\r
1077                                     Browser Protocol.\r
1078    \r
1079    @retval EFI_UNSUPPORTED        If the Framework HII module does not register Callback although it specify the opcode under\r
1080                                   focuse to be INTERRACTIVE.\r
1081    @retval EFI_SUCCESS            The callback complete successfully.\r
1082    @retval !EFI_SUCCESS           The error code returned by EFI_FORM_CALLBACK_PROTOCOL.Callback.\r
1083    \r
1084  **/\r
1085 EFI_STATUS\r
1086 EFIAPI\r
1087 ThunkCallback (\r
1088   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,\r
1089   IN  EFI_BROWSER_ACTION                     Action,\r
1090   IN  EFI_QUESTION_ID                        QuestionId,\r
1091   IN  UINT8                                  Type,\r
1092   IN  EFI_IFR_TYPE_VALUE                     *Value,\r
1093   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest\r
1094   )\r
1095 {\r
1096   EFI_STATUS                                  Status;\r
1097   CONFIG_ACCESS_PRIVATE                       *ConfigAccess;\r
1098   EFI_FORM_CALLBACK_PROTOCOL                  *FormCallbackProtocol;\r
1099   EFI_HII_CALLBACK_PACKET                     *Packet;\r
1100   EFI_IFR_DATA_ARRAY                          *Data;\r
1101   EFI_IFR_DATA_ENTRY                          *DataEntry;\r
1102   UINT16                                      KeyValue;\r
1103   ONE_OF_OPTION_MAP_ENTRY                     *OneOfOptionMapEntry;\r
1104   EFI_HANDLE                                  NotifyHandle;\r
1105   EFI_INPUT_KEY                               Key;  \r
1106   BOOLEAN                                     NvMapAllocated;\r
1107 \r
1108   if ((Action == EFI_BROWSER_ACTION_FORM_OPEN) || (Action == EFI_BROWSER_ACTION_FORM_CLOSE)) {\r
1109     //\r
1110     // Ignore UEFI OPEN/CLOSE Action for FrameworkCallback\r
1111     //\r
1112     return EFI_SUCCESS;\r
1113   }\r
1114 \r
1115   ASSERT (This != NULL);\r
1116   ASSERT (Value != NULL);\r
1117   ASSERT (ActionRequest != NULL);\r
1118 \r
1119   *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
1120 \r
1121   ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
1122 \r
1123   FormCallbackProtocol = ConfigAccess->FormCallbackProtocol;\r
1124   if (FormCallbackProtocol == NULL) {\r
1125     ASSERT (FALSE);\r
1126     return EFI_UNSUPPORTED;\r
1127   }\r
1128 \r
1129   //\r
1130   // Check if the QuestionId match a OneOfOption.\r
1131   //\r
1132   OneOfOptionMapEntry = GetOneOfOptionMapEntry (ConfigAccess->ThunkContext, QuestionId, Type, Value);\r
1133 \r
1134   if (OneOfOptionMapEntry == NULL) {\r
1135     //\r
1136     // This is not a One-Of-Option opcode. QuestionId is the KeyValue\r
1137     //\r
1138     KeyValue = QuestionId;\r
1139   } else {\r
1140     //\r
1141     // Otherwise, use the original Key specified in One Of Option in the Framework VFR syntax.\r
1142     //\r
1143     KeyValue = OneOfOptionMapEntry->FwKey;\r
1144   }\r
1145 \r
1146   //\r
1147   // Build the EFI_IFR_DATA_ARRAY\r
1148   //\r
1149   Data = CreateIfrDataArray (ConfigAccess, QuestionId, Type, Value, &NvMapAllocated);\r
1150 \r
1151   Status = mHiiDatabase->RegisterPackageNotify (\r
1152                            mHiiDatabase,\r
1153                            EFI_HII_PACKAGE_FORMS,\r
1154                            NULL,\r
1155                            FormUpdateNotify,\r
1156                            EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,\r
1157                            &NotifyHandle\r
1158                            );\r
1159   //\r
1160   //Call the Framework Callback function.\r
1161   //\r
1162   Packet =  NULL;\r
1163   Status =  FormCallbackProtocol->Callback (\r
1164               FormCallbackProtocol,\r
1165               KeyValue,\r
1166               Data,\r
1167               &Packet\r
1168               );\r
1169   SyncBrowserDataForNvMapOverride (ConfigAccess, QuestionId);\r
1170 \r
1171   //\r
1172   // Callback require browser to perform action\r
1173   //\r
1174   if (EFI_ERROR (Status)) {\r
1175     if (Packet != NULL) {\r
1176       do {\r
1177         CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, Packet->String, NULL);\r
1178       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
1179     }\r
1180     //\r
1181     // Error Code in Status is discarded.\r
1182     //\r
1183   } else {\r
1184     if (Packet != NULL) {\r
1185         if (Packet->DataArray.EntryCount  == 1 && Packet->DataArray.NvRamMap == NULL) {\r
1186           DataEntry = (EFI_IFR_DATA_ENTRY *) ((UINT8 *) Packet + sizeof (EFI_IFR_DATA_ARRAY));\r
1187           if ((DataEntry->Flags & EXIT_REQUIRED) == EXIT_REQUIRED) {\r
1188               *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
1189           }\r
1190 \r
1191           if ((DataEntry->Flags & SAVE_REQUIRED) == SAVE_REQUIRED) {\r
1192             Status = ConfigAccess->ConfigAccessProtocol.RouteConfig (\r
1193                                       &ConfigAccess->ConfigAccessProtocol,\r
1194                                       NULL,\r
1195                                       NULL\r
1196                                       );\r
1197           }\r
1198         }\r
1199         FreePool (Packet);\r
1200     }\r
1201   }\r
1202 \r
1203   //\r
1204   // Unregister notify for Form package update\r
1205   //\r
1206   Status = mHiiDatabase->UnregisterPackageNotify (\r
1207                            mHiiDatabase,\r
1208                            NotifyHandle\r
1209                            );\r
1210   //\r
1211   // UEFI SetupBrowser behaves differently with Framework SetupBrowser when call back function \r
1212   // update any forms in HII database. UEFI SetupBrowser will re-parse the displaying form package and load\r
1213   // the values from variable storages. Framework SetupBrowser will only re-parse the displaying form packages.\r
1214   // To make sure customer's previous changes is saved and the changing question behaves as expected, we\r
1215   // issue a EFI_BROWSER_ACTION_REQUEST_SUBMIT to ask UEFI SetupBrowser to save the changes proceed to re-parse\r
1216   // the form and load all the variable storages.\r
1217   //\r
1218   if (*ActionRequest == EFI_BROWSER_ACTION_REQUEST_NONE && mHiiPackageListUpdated) {\r
1219     mHiiPackageListUpdated= FALSE;\r
1220     *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
1221   } else {\r
1222     if (ConfigAccess->ThunkContext->FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS ||\r
1223         ConfigAccess->ThunkContext->FormSet->SubClass == EFI_SINGLE_USE_SUBCLASS) {\r
1224       *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
1225     }\r
1226   }\r
1227 \r
1228 \r
1229   //\r
1230   // Clean up.\r
1231   //\r
1232   DestroyIfrDataArray (Data, NvMapAllocated);\r
1233   \r
1234   return Status;\r
1235 }\r
1236 \r