]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkCompatibilityPkg/Compatibility/FrameworkHiiToUefiHiiThunk/ConfigAccess.c
clean up for IPF ICC tool chain.
[mirror_edk2.git] / EdkCompatibilityPkg / Compatibility / FrameworkHiiToUefiHiiThunk / ConfigAccess.c
index bac07de530819a2dfd6b73f8710e6524e299faad..edbc34a3e49f4cdc2eb4575ec9fb9cdad7742887 100644 (file)
@@ -1,7 +1,7 @@
 /**@file\r
-  This file contains functions related to Config Access Protocols installed by\r
-  by HII Thunk Modules which is used to thunk UEFI Config Access Callback to \r
-  Framework HII Callback.\r
+  This file implements functions related to Config Access Protocols installed by\r
+  by HII Thunk Modules. These Config access Protocols are used to thunk UEFI Config \r
+  Access Callback to Framework HII Callback and EFI Variable Set/Get operations.\r
   \r
 Copyright (c) 2008, Intel Corporation\r
 All rights reserved. This program and the accompanying materials\r
@@ -15,254 +15,256 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 **/\r
 \r
 #include "HiiDatabase.h"\r
+#include "UefiIfrParser.h"\r
 \r
-HII_TRHUNK_CONFIG_ACCESS_PROTOCOL_INSTANCE ConfigAccessProtocolInstanceTempate = {\r
-  HII_TRHUNK_CONFIG_ACCESS_PROTOCOL_INSTANCE_SIGNATURE,\r
+BOOLEAN            mHiiPackageListUpdated = FALSE;\r
+\r
+CONFIG_ACCESS_PRIVATE gConfigAccessPrivateTempate = {\r
+  CONFIG_ACCESS_PRIVATE_SIGNATURE,\r
   {\r
     ThunkExtractConfig,\r
     ThunkRouteConfig,\r
     ThunkCallback\r
   }, //ConfigAccessProtocol\r
-  NULL, //FrameworkFormCallbackProtocol\r
-  {NULL, NULL} //ConfigAccessStorageListHead\r
+  NULL, //FormCallbackProtocol\r
+  NULL \r
 };\r
 \r
 /**\r
-   Find and return the pointer to Package Header of the Form package\r
-   in the Framework Package List. The Framework Package List is created\r
-   by a module calling the Framework HII interface.\r
-   The Framwork Package List contains package data \r
-   generated by Intel's UEFI VFR Compiler and String gather tool. The data format\r
-   of the package data is defined by  TIANO_AUTOGEN_PACKAGES_HEADER.\r
-\r
-   If the package list contains other type of packages such as KEYBOARD_LAYOUT,\r
-   FONTS and IMAGES, the ASSERT. This is to make sure the caller is a \r
-   Framework Module which does not include packages introduced by UEFI Specification\r
-   or packages that is not supported by Thunk layer.\r
+  Get the first EFI_IFR_VARSTORE from the FormSet. \r
+    \r
+  @param FormSet                  The Form Set.\r
+   \r
+  @retval FORMSET_STORAGE *       Return the first EFI_IFR_VARSTORE.\r
+  @retval NULL                    If the Form Set does not have EFI_IFR_VARSTORE.\r
+**/\r
+FORMSET_STORAGE *\r
+GetFirstStorageOfFormSet (\r
+  IN CONST FORM_BROWSER_FORMSET * FormSet\r
+  ) \r
+{\r
+  LIST_ENTRY             *StorageList;\r
+  FORMSET_STORAGE        *Storage;\r
+\r
+  StorageList = GetFirstNode (&FormSet->StorageListHead);\r
+\r
+  if (!IsNull (&FormSet->StorageListHead, StorageList)) {\r
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageList);\r
+    return Storage;\r
+  }\r
+  \r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Get the EFI_IFR_VARSTORE where the Question's value is stored.\r
     \r
-   @param Packages    The Framework Package List\r
+  @param FormSet                  The Form Set.\r
    \r
-   @retval EFI_HII_PACKAGE_HEADER* Return the Package Header of\r
-                                                          Form Package.\r
-   @retval NULL                                    If no Form Package is found.\r
+  @retval FORMSET_STORAGE *       The EFI_IFR_VARSTORE where the Question's value is stored.\r
+  @retval NULL                    If the Form Set does not have EFI_IFR_VARSTORE.\r
 **/\r
-EFI_HII_PACKAGE_HEADER *\r
-GetIfrFormSet (\r
-  IN  CONST EFI_HII_PACKAGES  *Packages\r
+FORMSET_STORAGE *\r
+GetStorageFromQuestionId (\r
+  IN CONST FORM_BROWSER_FORMSET * FormSet,\r
+  IN       EFI_QUESTION_ID        QuestionId\r
   )\r
 {\r
-  TIANO_AUTOGEN_PACKAGES_HEADER **TianoAutogenPackageHdrArray;\r
-  EFI_HII_PACKAGE_HEADER        *IfrPackage;\r
-  UINTN                         Index;\r
+  LIST_ENTRY             *FormList;\r
+  LIST_ENTRY             *StatementList;\r
+  FORM_BROWSER_FORM      *Form;\r
+  FORM_BROWSER_STATEMENT *Statement;\r
+\r
+  FormList = GetFirstNode (&FormSet->FormListHead);\r
+\r
+  while (!IsNull (&FormSet->FormListHead, FormList)) {\r
+    Form = FORM_BROWSER_FORM_FROM_LINK (FormList);\r
+\r
+    StatementList = GetFirstNode (&Form->StatementListHead);\r
+\r
+    while (!IsNull (&Form->StatementListHead, StatementList)) {\r
+      Statement = FORM_BROWSER_STATEMENT_FROM_LINK (StatementList);\r
+      if ((QuestionId == Statement->QuestionId) && (Statement->Storage != NULL)) {\r
+        //\r
+        // UEFI Question ID is unique in a FormSet.\r
+        //\r
+        ASSERT (Statement->Storage->Type == EFI_HII_VARSTORE_BUFFER);\r
+        return Statement->Storage;\r
+      }\r
+      StatementList = GetNextNode (&Form->StatementListHead, StatementList);\r
+    }\r
 \r
-  ASSERT (Packages != NULL);\r
+    FormList = GetNextNode (&FormSet->FormListHead, FormList);\r
+  }\r
+  \r
+  return NULL;\r
+}\r
 \r
-  IfrPackage = NULL;\r
+/**\r
+  Get the EFI_IFR_VARSTORE based the ID.\r
+    \r
+  @param FormSet                  The Form Set.\r
+   \r
+  @retval FORMSET_STORAGE *       The EFI_IFR_VARSTORE with the ID.\r
+  @retval NULL                    If the Form Set does not have EFI_IFR_VARSTORE with such ID.\r
+**/\r
+FORMSET_STORAGE *\r
+GetStorageFromVarStoreId (\r
+  IN CONST FORM_BROWSER_FORMSET * FormSet,\r
+  IN       EFI_VARSTORE_ID        VarStoreId\r
+  )\r
+{\r
+  LIST_ENTRY             *StorageList;\r
+  FORMSET_STORAGE        *Storage;\r
 \r
-  TianoAutogenPackageHdrArray = (TIANO_AUTOGEN_PACKAGES_HEADER **) (((UINT8 *) &Packages->GuidId) + sizeof (Packages->GuidId));\r
-  for (Index = 0; Index < Packages->NumberOfPackages; Index++) {\r
-    //\r
-    // BugBug: The current UEFI HII build tool generate a binary in the format defined in: \r
-    // TIANO_AUTOGEN_PACKAGES_HEADER. We assume that all packages generated in\r
-    // this binary is with same package type. So the returned IfrPackNum and StringPackNum\r
-    // may not be the exact number of valid package number in the binary generated \r
-    // by HII Build tool.\r
-    //\r
-    switch (TianoAutogenPackageHdrArray[Index]->PackageHeader.Type) {\r
-      case EFI_HII_PACKAGE_FORM:\r
-        return &TianoAutogenPackageHdrArray[Index]->PackageHeader;\r
-        break;\r
+  StorageList = GetFirstNode (&FormSet->StorageListHead);\r
 \r
-      case EFI_HII_PACKAGE_STRINGS:\r
-      case EFI_HII_PACKAGE_SIMPLE_FONTS:\r
-        break;\r
+  while (!IsNull (&FormSet->StorageListHead, StorageList)) {\r
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageList);\r
 \r
-      //\r
-      // The following fonts are invalid for a module that using Framework to UEFI thunk layer.\r
-      //\r
-      case EFI_HII_PACKAGE_KEYBOARD_LAYOUT:\r
-      case EFI_HII_PACKAGE_FONTS:\r
-      case EFI_HII_PACKAGE_IMAGES:\r
-      default:\r
-        ASSERT (FALSE);\r
-        break;\r
+    if (VarStoreId == Storage->VarStoreId) {\r
+      return Storage;\r
     }\r
-  }\r
 \r
-  return (EFI_HII_PACKAGE_HEADER *) NULL;\r
+    StorageList = GetNextNode (&FormSet->StorageListHead, StorageList);\r
+  }\r
+  \r
+  return NULL;\r
 }\r
 \r
 /**\r
-  This function scan EFI_IFR_VARSTORE_OP in the Form Package.\r
-  It create entries for these VARSTORE found and append the entry\r
-  to a Link List.\r
-\r
-  If FormSetPackage is not EFI_HII_PACKAGE_FORM, then ASSERT.\r
-  If there is no linear buffer storage in this formset, then ASSERT.\r
-\r
-   @param FormSetPackage            The Form Package header.\r
-   @param BufferStorageListHead    The link list for the VARSTORE found in the form package.\r
+  Get the EFI_IFR_VARSTORE based the <ConfigHdr> string in a <ConfigRequest>\r
+  or a <ConfigResp> string.\r
+    \r
+  @param FormSet                  The Form Set.\r
+  @param ConfigString             The Configuration String which is defined by UEFI HII.\r
    \r
-   @retval  EFI_SUCCESS                     The function scan the form set and find one or more \r
-                                                          VARSTOREs.\r
-   @retval  EFI_OUT_OF_RESOURCES    There is not enough memory to complete the function.\r
+  @retval FORMSET_STORAGE *       The EFI_IFR_VARSTORE where the Question's value is stored.\r
+  @retval NULL                    If the Form Set does not have EFI_IFR_VARSTORE with such ID.\r
 **/\r
-EFI_STATUS\r
-GetBufferStorage  (\r
-  IN  CONST EFI_HII_PACKAGE_HEADER *FormSetPackage,\r
-  OUT       LIST_ENTRY             *BufferStorageListHead\r
+FORMSET_STORAGE *\r
+GetStorageFromConfigString (\r
+  IN CONST FORM_BROWSER_FORMSET *FormSet,\r
+  IN  CONST EFI_STRING          ConfigString\r
   )\r
 {\r
-  UINTN                   OpCodeOffset;\r
-  UINTN                   OpCodeLength;\r
-  UINT8                   *OpCodeData;\r
-  UINT8                   Operand;\r
-  EFI_IFR_VARSTORE        *VarStoreOpCode;\r
-  HII_TRHUNK_BUFFER_STORAGE_KEY *BufferStorageKey;\r
-\r
-  ASSERT (FormSetPackage->Type == EFI_HII_PACKAGE_FORM);\r
-\r
-  OpCodeOffset = sizeof (EFI_HII_PACKAGE_HEADER);\r
-  while (OpCodeOffset < FormSetPackage->Length) {\r
-    OpCodeData = (UINT8 *) FormSetPackage + OpCodeOffset;\r
-\r
-    OpCodeLength = ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;\r
-    OpCodeOffset += OpCodeLength;\r
-    Operand = ((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode;\r
-\r
-    if (Operand == EFI_IFR_VARSTORE_OP) {\r
-      VarStoreOpCode = (EFI_IFR_VARSTORE *)OpCodeData;\r
-      BufferStorageKey = AllocateZeroPool (sizeof (*BufferStorageKey));\r
-      if (BufferStorageKey == NULL) {\r
-        return EFI_OUT_OF_RESOURCES;\r
-      }\r
-      CopyMem (&BufferStorageKey->Guid, &VarStoreOpCode->Guid, sizeof (EFI_GUID));\r
-      \r
-      BufferStorageKey->Name = AllocateZeroPool (AsciiStrSize (VarStoreOpCode->Name) * 2);\r
-      AsciiStrToUnicodeStr (VarStoreOpCode->Name, BufferStorageKey->Name);\r
+  LIST_ENTRY             *StorageList;\r
+  FORMSET_STORAGE        *Storage;\r
 \r
-      BufferStorageKey->VarStoreId = VarStoreOpCode->VarStoreId;\r
+  StorageList = GetFirstNode (&FormSet->StorageListHead);\r
 \r
-      BufferStorageKey->Size = VarStoreOpCode->Size;\r
-      BufferStorageKey->Signature = HII_TRHUNK_BUFFER_STORAGE_KEY_SIGNATURE;\r
+  while (!IsNull (&FormSet->StorageListHead, StorageList)) {\r
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageList);\r
 \r
-      InsertTailList (BufferStorageListHead, &BufferStorageKey->List);\r
+    if (IsConfigHdrMatch (ConfigString, &Storage->Guid, Storage->Name)) {\r
+      return Storage;\r
     }\r
+\r
+    StorageList = GetNextNode (&FormSet->StorageListHead, StorageList);\r
   }\r
 \r
-  return EFI_SUCCESS;\r
+   return NULL;\r
 }\r
-  \r
+\r
 /**\r
   This function installs a EFI_CONFIG_ACCESS_PROTOCOL instance for a form package registered\r
   by a module using Framework HII Protocol Interfaces.\r
 \r
-   UEFI HII require EFI_HII_CONFIG_ACCESS_PROTOCOL to be installed on a EFI_HANDLE, so\r
-   that Setup Utility can load the Buffer Storage using this protocol.\r
+  UEFI HII require EFI_HII_CONFIG_ACCESS_PROTOCOL to be installed on a EFI_HANDLE, so\r
+  that Setup Utility can load the Buffer Storage using this protocol.\r
    \r
-   @param Packages          The framework package list.\r
-   @param MapEntry          The Thunk Layer Handle Mapping Database Entry.\r
+  @param Packages             The Package List.\r
+  @param ThunkContext         The Thunk Context.\r
    \r
-   @retval  EFI_SUCCESS             The Config Access Protocol is installed successfully.\r
-   @retval  EFI_OUT_RESOURCE    There is not enough memory.\r
+  @retval  EFI_SUCCESS        The Config Access Protocol is installed successfully.\r
+  @retval  EFI_OUT_RESOURCE   There is not enough memory.\r
    \r
 **/\r
 EFI_STATUS\r
-InstallDefaultUefiConfigAccessProtocol (\r
-  IN  CONST EFI_HII_PACKAGES                         *Packages,\r
-  IN  OUT   HII_TRHUNK_HANDLE_MAPPING_DATABASE_ENTRY *MapEntry\r
+InstallDefaultConfigAccessProtocol (\r
+  IN  CONST EFI_HII_PACKAGES                    *Packages,\r
+  IN  OUT   HII_THUNK_CONTEXT                   *ThunkContext\r
   )\r
 {\r
-  EFI_HII_PACKAGE_HEADER                      *FormSetPackage;\r
   EFI_STATUS                                  Status;\r
-  HII_TRHUNK_CONFIG_ACCESS_PROTOCOL_INSTANCE  *ConfigAccessInstance;\r
+  CONFIG_ACCESS_PRIVATE                       *ConfigAccessInstance;\r
+\r
+  ASSERT (ThunkContext->IfrPackageCount != 0);\r
 \r
-  Status = HiiLibCreateHiiDriverHandle (&MapEntry->UefiHiiDriverHandle);\r
+  Status = HiiLibCreateHiiDriverHandle (&ThunkContext->UefiHiiDriverHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
   ConfigAccessInstance = AllocateCopyPool (\r
-                           sizeof (HII_TRHUNK_CONFIG_ACCESS_PROTOCOL_INSTANCE), \r
-                           &ConfigAccessProtocolInstanceTempate\r
+                           sizeof (CONFIG_ACCESS_PRIVATE), \r
+                           &gConfigAccessPrivateTempate\r
                            );\r
   ASSERT (ConfigAccessInstance != NULL);\r
-  InitializeListHead (&ConfigAccessInstance->ConfigAccessBufferStorageListHead);\r
-\r
-  //\r
-  // We assume there is only one formset package in each Forms Package\r
-  //\r
-  FormSetPackage = GetIfrFormSet (Packages);\r
-  ASSERT (FormSetPackage != NULL);\r
   \r
-  Status = GetBufferStorage (FormSetPackage, &ConfigAccessInstance->ConfigAccessBufferStorageListHead);\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (ConfigAccessInstance);\r
-    ASSERT (FALSE);\r
-    return Status;\r
-  }\r
-\r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
-          &MapEntry->UefiHiiDriverHandle,\r
+          &ThunkContext->UefiHiiDriverHandle,\r
           &gEfiHiiConfigAccessProtocolGuid,\r
           &ConfigAccessInstance->ConfigAccessProtocol,\r
           NULL\r
           );\r
   ASSERT_EFI_ERROR (Status);\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool  (ConfigAccessInstance);\r
-    return Status;\r
-  }\r
+  \r
+  ConfigAccessInstance->ThunkContext = ThunkContext;\r
   \r
   return EFI_SUCCESS;\r
 }\r
 \r
 /**\r
+  This function un-installs the EFI_CONFIG_ACCESS_PROTOCOL instance for a form package registered\r
+  by a module using Framework HII Protocol Interfaces.\r
 \r
-   Wrap EFI_HII_CONFIG_ACCESS_PROTOCOL.RouteConfig to a call to EFI_FORM_CALLBACK_PROTOCOL.NvWrite.\r
-   \r
-   @param BufferStorageKey               The key with all attributes needed to call EFI_FORM_CALLBACK_PROTOCOL.NvWrite.\r
-   @param FrameworkFormCallBack     The EFI_FORM_CALLBACK_PROTOCOL registered by Framework HII module.\r
-   @param Data                                  The data to be saved.\r
-   @param DataSize                            The size of data.\r
+  ASSERT if no Config Access is found for such pakcage list or failed to uninstall the protocol.\r
+\r
+  @param ThunkContext         The Thunk Context.\r
    \r
-   @retval EFI_STATUS                       The status returned by the EFI_FORM_CALLBACK_PROTOCOL.NvWrite.\r
- **/\r
-EFI_STATUS\r
-RouteConfigToFrameworkFormCallBack (\r
-  IN       HII_TRHUNK_BUFFER_STORAGE_KEY              *BufferStorageKey,\r
-  IN       EFI_FORM_CALLBACK_PROTOCOL                 *FrameworkFormCallBack,\r
-  IN       VOID                                       *Data,\r
-  IN       UINTN                                      DataSize\r
+**/\r
+VOID\r
+UninstallDefaultConfigAccessProtocol (\r
+  IN  HII_THUNK_CONTEXT                   *ThunkContext\r
   )\r
 {\r
-  EFI_STATUS          Status;\r
-  BOOLEAN             ResetRequired;\r
+  EFI_STATUS                      Status;\r
+  EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
+  \r
+  HiiLibDestroyHiiDriverHandle (ThunkContext->UefiHiiDriverHandle);\r
+\r
+  Status = gBS->HandleProtocol (\r
+                  ThunkContext->UefiHiiDriverHandle,\r
+                  &gEfiHiiConfigAccessProtocolGuid,\r
+                  (VOID **) &ConfigAccess\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gBS->UninstallProtocolInterface (\r
+                  ThunkContext->UefiHiiDriverHandle,\r
+                  &gEfiHiiConfigAccessProtocolGuid,\r
+                  ConfigAccess\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
 \r
-  Status = FrameworkFormCallBack->NvWrite (\r
-              FrameworkFormCallBack,  \r
-              BufferStorageKey->Name,\r
-              &BufferStorageKey->Guid,\r
-              EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
-              DataSize,\r
-              Data,\r
-              &ResetRequired\r
-              );\r
-  return Status;\r
 }\r
+  \r
 \r
 /**\r
    Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to EFI_FORM_CALLBACK_PROTOCOL.NvRead.\r
    \r
-   @param BufferStorageKey               The key with all attributes needed to call EFI_FORM_CALLBACK_PROTOCOL.NvRead.\r
-   @param FrameworkFormCallBack     The EFI_FORM_CALLBACK_PROTOCOL registered by Framework HII module.\r
-   @param Data                                  The data read.\r
-   @param DataSize                            The size of data.\r
+   @param BufferStorage         The key with all attributes needed to call EFI_FORM_CALLBACK_PROTOCOL.NvRead.\r
+   @param FwFormCallBack    The EFI_FORM_CALLBACK_PROTOCOL registered by Framework HII module.\r
+   @param Data                     The data read.\r
+   @param DataSize                 The size of data.\r
    \r
-   @retval EFI_STATUS                       The status returned by the EFI_FORM_CALLBACK_PROTOCOL.NvWrite.\r
+   @retval EFI_STATUS              The status returned by the EFI_FORM_CALLBACK_PROTOCOL.NvWrite.\r
    @retval EFI_INVALID_PARAMETER   If the EFI_FORM_CALLBACK_PROTOCOL.NvRead return the size information of the data\r
-                                                        does not match what has been recorded early in he HII_TRHUNK_BUFFER_STORAGE_KEY.\r
+                                   does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r
  **/\r
 EFI_STATUS\r
-ExtractConfigFromFrameworkFormCallBack (\r
-  IN       HII_TRHUNK_BUFFER_STORAGE_KEY              *BufferStorageKey,\r
-  IN       EFI_FORM_CALLBACK_PROTOCOL                 *FrameworkFormCallBack,\r
+CallFormCallBack (\r
+  IN       FORMSET_STORAGE                            *BufferStorage,\r
+  IN       EFI_FORM_CALLBACK_PROTOCOL                 *FwFormCallBack,\r
   OUT      VOID                                       **Data,\r
   OUT      UINTN                                      *DataSize\r
   )\r
@@ -272,16 +274,16 @@ ExtractConfigFromFrameworkFormCallBack (
   *DataSize = 0;\r
   *Data     = NULL;\r
   \r
-  Status = FrameworkFormCallBack->NvRead (\r
-              FrameworkFormCallBack,  \r
-              BufferStorageKey->Name,\r
-              &BufferStorageKey->Guid,\r
+  Status = FwFormCallBack->NvRead (\r
+              FwFormCallBack,  \r
+              BufferStorage->Name,\r
+              &BufferStorage->Guid,\r
               NULL,\r
               DataSize,\r
               *Data\r
               );\r
   if (Status == EFI_BUFFER_TOO_SMALL) {\r
-    if (BufferStorageKey->Size != *DataSize) {\r
+    if (BufferStorage->Size != *DataSize) {\r
       ASSERT (FALSE);\r
       return EFI_INVALID_PARAMETER;\r
     }\r
@@ -291,10 +293,10 @@ ExtractConfigFromFrameworkFormCallBack (
       return EFI_OUT_OF_RESOURCES;\r
     }\r
 \r
-    FrameworkFormCallBack->NvRead (\r
-                  FrameworkFormCallBack,  \r
-                  BufferStorageKey->Name,\r
-                  &BufferStorageKey->Guid,\r
+    FwFormCallBack->NvRead (\r
+                  FwFormCallBack,  \r
+                  BufferStorage->Name,\r
+                  &BufferStorage->Guid,\r
                   NULL,\r
                   DataSize,\r
                   *Data\r
@@ -304,52 +306,26 @@ ExtractConfigFromFrameworkFormCallBack (
   return Status;\r
 }\r
 \r
-/**\r
-   Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to UEFI Variable Set Service.\r
-   \r
-   @param BufferStorageKey               The key with all attributes needed to call a UEFI Variable Get Service.\r
-   @param Data                                  The data read.\r
-   @param DataSize                            The size of data.\r
-\r
-   @retval EFI_STATUS                       The status returned by the UEFI Variable Set Service.\r
-   \r
- **/\r
-EFI_STATUS\r
-RouteConfigToUefiVariable (\r
-  IN       HII_TRHUNK_BUFFER_STORAGE_KEY              *BufferStorageKey,\r
-  IN       VOID                                       *Data,\r
-  IN       UINTN                                      DataSize\r
-  )\r
-{\r
-  return gRT->SetVariable (\r
-                  BufferStorageKey->Name,\r
-                  &BufferStorageKey->Guid,\r
-                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
-                  DataSize,\r
-                  Data\r
-                  );\r
-  \r
-}\r
 \r
 /**\r
    Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.ExtractConfig to a call to UEFI Variable Get Service.\r
    \r
-   @param BufferStorageKey               The key with all attributes needed to call a UEFI Variable Get Service.\r
-   @param Data                                  The data read.\r
-   @param DataSize                            The size of data.\r
+   @param BufferStorage        The key with all attributes needed to call a UEFI Variable Get Service.\r
+   @param Data                    The data read.\r
+   @param DataSize                The size of data.\r
 \r
    If the UEFI Variable Get Service return the size information of the data\r
-   does not match what has been recorded early in he HII_TRHUNK_BUFFER_STORAGE_KEY.\r
+   does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r
    then ASSERT.\r
                                                         \r
-   @retval EFI_STATUS                       The status returned by the UEFI Variable Get Service.\r
+   @retval EFI_STATUS              The status returned by the UEFI Variable Get Service.\r
    @retval EFI_INVALID_PARAMETER   If the UEFI Variable Get Service return the size information of the data\r
-                                                        does not match what has been recorded early in he HII_TRHUNK_BUFFER_STORAGE_KEY.\r
+                                   does not match what has been recorded early in he BUFFER_STORAGE_ENTRY.\r
  **/\r
 \r
 EFI_STATUS\r
-ExtractConfigFromUefiVariable (\r
-  IN       HII_TRHUNK_BUFFER_STORAGE_KEY              *BufferStorageKey,\r
+GetUefiVariable (\r
+  IN       FORMSET_STORAGE                            *BufferStorage,\r
   OUT      VOID                                       **Data,\r
   OUT      UINTN                                      *DataSize\r
   )\r
@@ -359,15 +335,15 @@ ExtractConfigFromUefiVariable (
   *DataSize = 0;\r
   *Data = NULL;\r
   Status = gRT->GetVariable (\r
-              BufferStorageKey->Name,\r
-              &BufferStorageKey->Guid,\r
+              BufferStorage->Name,\r
+              &BufferStorage->Guid,\r
               NULL,\r
               DataSize,\r
               *Data\r
               );\r
   if (Status == EFI_BUFFER_TOO_SMALL) {\r
 \r
-    if (BufferStorageKey->Size != *DataSize) {\r
+    if (BufferStorage->Size != *DataSize) {\r
       ASSERT (FALSE);\r
       return EFI_INVALID_PARAMETER;\r
     }\r
@@ -378,8 +354,8 @@ ExtractConfigFromUefiVariable (
     }\r
 \r
     Status = gRT->GetVariable (\r
-                BufferStorageKey->Name,\r
-                &BufferStorageKey->Guid,\r
+                BufferStorage->Name,\r
+                &BufferStorage->Guid,\r
                 NULL,\r
                 DataSize,\r
                 *Data\r
@@ -395,22 +371,22 @@ ExtractConfigFromUefiVariable (
   so that data can be read from the data storage such as UEFI Variable or module's\r
   customized storage exposed by EFI_FRAMEWORK_CALLBACK.\r
 \r
-   @param This          Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
+   @param This        Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
    @param Request     A null-terminated Unicode string in <ConfigRequest> format. Note that this\r
-                                includes the routing information as well as the configurable name / value pairs. It is\r
-                                invalid for this string to be in <MultiConfigRequest> format.\r
+                      includes the routing information as well as the configurable name / value pairs. It is\r
+                      invalid for this string to be in <MultiConfigRequest> format.\r
 \r
-   @param Progress   On return, points to a character in the Request string. Points to the string's null\r
-                               terminator if request was successful. Points to the most recent '&' before the first\r
-                                failing name / value pair (or the beginning of the string if the failure is in the first\r
-                                name / value pair) if the request was not successful\r
+   @param Progress    On return, points to a character in the Request string. Points to the string's null\r
+                      terminator if request was successful. Points to the most recent '&' before the first\r
+                      failing name / value pair (or the beginning of the string if the failure is in the first\r
+                      name / value pair) if the request was not successful\r
    @param Results     A null-terminated Unicode string in <ConfigAltResp> format which has all\r
-                              values filled in for the names in the Request string. String to be allocated by the called\r
-                              function.\r
+                      values filled in for the names in the Request string. String to be allocated by the called\r
+                      function.\r
    \r
    @retval EFI_INVALID_PARAMETER   If there is no Buffer Storage for this Config Access instance.\r
-   @retval EFI_SUCCESS                    The setting is retrived successfully.\r
-   @retval !EFI_SUCCESS                  The error returned by UEFI Get Variable or Framework Form Callback Nvread.\r
+   @retval EFI_SUCCESS             The setting is retrived successfully.\r
+   @retval !EFI_SUCCESS            The error returned by UEFI Get Variable or Framework Form Callback Nvread.\r
  **/\r
 EFI_STATUS\r
 EFIAPI\r
@@ -422,40 +398,47 @@ ThunkExtractConfig (
   )\r
 {\r
   EFI_STATUS                                  Status;\r
-  HII_TRHUNK_CONFIG_ACCESS_PROTOCOL_INSTANCE  *ConfigaAccessInstance;\r
-  LIST_ENTRY                                  *ListEntry;\r
-  HII_TRHUNK_BUFFER_STORAGE_KEY               *BufferStorageKey;\r
+  CONFIG_ACCESS_PRIVATE                       *ConfigAccess;\r
+  FORMSET_STORAGE                             *BufferStorage;\r
   VOID                                        *Data;\r
   UINTN                                       DataSize;\r
 \r
   Data = NULL;\r
-  ConfigaAccessInstance = HII_TRHUNK_CONFIG_ACCESS_PROTOCOL_INSTANCE_FROM_PROTOCOL (This);\r
+  ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
 \r
-  //\r
-  // For now, only one var varstore is supported so that we don't need to parse the Configuration string.\r
-  //\r
-  ListEntry = GetFirstNode (&ConfigaAccessInstance->ConfigAccessBufferStorageListHead);\r
-  if (ListEntry == NULL) {\r
-    ASSERT (FALSE);\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-  \r
-  BufferStorageKey = HII_TRHUNK_BUFFER_STORAGE_KEY_FROM_LIST_ENTRY (ListEntry);\r
-\r
-  if (ConfigaAccessInstance->FrameworkFormCallbackProtocol == NULL ||\r
-      ConfigaAccessInstance->FrameworkFormCallbackProtocol->NvRead == NULL) {\r
-    Status = ExtractConfigFromUefiVariable (\r
-               BufferStorageKey,\r
-               &Data,\r
-               &DataSize\r
-               );\r
+  BufferStorage = GetStorageFromConfigString (ConfigAccess->ThunkContext->FormSet, Request);\r
+\r
+  if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
+    //\r
+    // NvMapOverride is not used. Get the Storage data from EFI Variable or Framework Form Callback.\r
+    //\r
+    if (ConfigAccess->FormCallbackProtocol == NULL ||\r
+        ConfigAccess->FormCallbackProtocol->NvRead == NULL) {\r
+      Status = GetUefiVariable (\r
+                 BufferStorage,\r
+                 &Data,\r
+                 &DataSize\r
+                 );\r
+    } else {\r
+      Status = CallFormCallBack (\r
+                 BufferStorage,\r
+                 ConfigAccess->FormCallbackProtocol,\r
+                  &Data,\r
+                  &DataSize\r
+                 );\r
+    }\r
   } else {\r
-    Status = ExtractConfigFromFrameworkFormCallBack (\r
-               BufferStorageKey,\r
-               ConfigaAccessInstance->FrameworkFormCallbackProtocol,\r
-                &Data,\r
-                &DataSize\r
-               );\r
+    //\r
+    // Use the NvMapOverride.\r
+    //\r
+    DataSize = BufferStorage->Size;\r
+    Data = AllocateCopyPool (DataSize, ConfigAccess->ThunkContext->NvMapOverride);\r
+    \r
+    if (Data != NULL) {\r
+      Status = EFI_SUCCESS;\r
+    } else {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+    }\r
   }\r
   \r
   if (!EFI_ERROR (Status)) {\r
@@ -469,25 +452,26 @@ ThunkExtractConfig (
                                             );\r
   }\r
 \r
-  SafeFreePool (Data);\r
+  if (Data != NULL) {\r
+    FreePool (Data);\r
+  }\r
   return Status;\r
 }\r
 \r
 /**\r
-\r
   This function implement the EFI_HII_CONFIG_ACCESS_PROTOCOL.RouteConfig\r
   so that data can be written to the data storage such as UEFI Variable or module's\r
   customized storage exposed by EFI_FRAMEWORK_CALLBACK.\r
    \r
-   @param This              Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
-   @param Configuration A null-terminated Unicode string in <ConfigResp> format.\r
+   @param This             Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
+   @param Configuration    A null-terminated Unicode string in <ConfigResp> format.\r
    @param Progress         A pointer to a string filled in with the offset of the most recent '&' before the first\r
-                                     failing name / value pair (or the beginning of the string if the failure is in the first\r
-                                     name / value pair) or the terminating NULL if all was successful.\r
+                           failing name / value pair (or the beginning of the string if the failure is in the first\r
+                           name / value pair) or the terminating NULL if all was successful.\r
    \r
    @retval EFI_INVALID_PARAMETER   If there is no Buffer Storage for this Config Access instance.\r
-   @retval EFI_SUCCESS                    The setting is saved successfully.\r
-   @retval !EFI_SUCCESS                  The error returned by UEFI Set Variable or Framework Form Callback Nvwrite.\r
+   @retval EFI_SUCCESS             The setting is saved successfully.\r
+   @retval !EFI_SUCCESS            The error returned by UEFI Set Variable or Framework Form Callback Nvwrite.\r
 **/   \r
 EFI_STATUS\r
 EFIAPI\r
@@ -498,31 +482,53 @@ ThunkRouteConfig (
   )\r
 {\r
   EFI_STATUS                                  Status;\r
-  HII_TRHUNK_CONFIG_ACCESS_PROTOCOL_INSTANCE  *ConfigaAccessInstance;\r
-  LIST_ENTRY                                  *ListEntry;\r
-  HII_TRHUNK_BUFFER_STORAGE_KEY               *BufferStorageKey;\r
+  CONFIG_ACCESS_PRIVATE                       *ConfigAccess;\r
+  FORMSET_STORAGE                             *BufferStorage;\r
   VOID                                        *Data;\r
   UINTN                                       DataSize;\r
+  UINTN                                       DataSize2;\r
   UINTN                                       LastModifiedByteIndex;\r
+  BOOLEAN                                     ResetRequired;\r
+  BOOLEAN                                     DataAllocated;\r
 \r
   Data = NULL;\r
-  ConfigaAccessInstance = HII_TRHUNK_CONFIG_ACCESS_PROTOCOL_INSTANCE_FROM_PROTOCOL (This);\r
-\r
-  //\r
-  // For now, only one var varstore is supported so that we don't need to parse the Configuration string.\r
-  //\r
-  ListEntry = GetFirstNode (&ConfigaAccessInstance->ConfigAccessBufferStorageListHead);\r
-  if (ListEntry == NULL) {\r
-    ASSERT (FALSE);\r
-    return EFI_INVALID_PARAMETER;\r
+  ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
+\r
+  BufferStorage = GetStorageFromConfigString (ConfigAccess->ThunkContext->FormSet, Configuration);\r
+\r
+  DataSize2     = BufferStorage->Size;\r
+  if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
+    DataAllocated = TRUE;\r
+    if (ConfigAccess->FormCallbackProtocol == NULL ||\r
+        ConfigAccess->FormCallbackProtocol->NvRead == NULL) {\r
+      Status = GetUefiVariable (\r
+                 BufferStorage,\r
+                 &Data,\r
+                 &DataSize\r
+                 );\r
+    } else {\r
+      Status = CallFormCallBack (\r
+                 BufferStorage,\r
+                 ConfigAccess->FormCallbackProtocol,\r
+                  &Data,\r
+                  &DataSize\r
+                 );\r
+    }\r
+  } else {\r
+    //\r
+    // ConfigToBlock will convert the Config String and update the NvMapOverride accordingly.\r
+    //\r
+    Status = EFI_SUCCESS;\r
+    Data = ConfigAccess->ThunkContext->NvMapOverride;\r
+    DataSize      = DataSize2;\r
+    DataAllocated = FALSE;\r
+  }  \r
+  if (EFI_ERROR (Status) || (DataSize2 != DataSize)) {\r
+    if (Data == NULL) {\r
+      Data = AllocateZeroPool (DataSize2);\r
+    }\r
   }\r
 \r
-  BufferStorageKey = HII_TRHUNK_BUFFER_STORAGE_KEY_FROM_LIST_ENTRY (ListEntry);\r
-\r
-  Data = AllocateZeroPool (BufferStorageKey->Size);\r
-  if (Data == NULL) {\r
-    return EFI_OUT_OF_RESOURCES;\r
-  }\r
   Status = mHiiConfigRoutingProtocol->ConfigToBlock (\r
                                           mHiiConfigRoutingProtocol,\r
                                           Configuration,\r
@@ -530,54 +536,372 @@ ThunkRouteConfig (
                                           &LastModifiedByteIndex,\r
                                           Progress\r
                                           );\r
-\r
   if (EFI_ERROR (Status)) {\r
     goto Done;\r
   }\r
 \r
-  DataSize = BufferStorageKey->Size;\r
-  if (ConfigaAccessInstance->FrameworkFormCallbackProtocol == NULL ||\r
-      ConfigaAccessInstance->FrameworkFormCallbackProtocol->NvRead == NULL) {\r
-    Status = RouteConfigToUefiVariable (\r
-               BufferStorageKey,\r
-               Data,\r
-               DataSize\r
-               );\r
-  } else {\r
-    Status = RouteConfigToFrameworkFormCallBack (\r
-               BufferStorageKey,\r
-               ConfigaAccessInstance->FrameworkFormCallbackProtocol,\r
-               Data,\r
-               DataSize\r
-               );\r
+  if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
+    if (ConfigAccess->FormCallbackProtocol == NULL ||\r
+        ConfigAccess->FormCallbackProtocol->NvWrite == NULL) {\r
+      Status = gRT->SetVariable (\r
+                    BufferStorage->Name,\r
+                    &BufferStorage->Guid,\r
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                    DataSize2,\r
+                    Data\r
+                    );\r
+    } else {\r
+      Status = ConfigAccess->FormCallbackProtocol->NvWrite (\r
+                    ConfigAccess->FormCallbackProtocol,  \r
+                    BufferStorage->Name,\r
+                    &BufferStorage->Guid,\r
+                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+                    DataSize2,\r
+                    Data,\r
+                    &ResetRequired\r
+                    );\r
+      \r
+    }\r
   }\r
 \r
-Done:  \r
-  SafeFreePool (Data);\r
+Done: \r
+  if (DataAllocated && (Data != NULL)) {\r
+    FreePool (Data);\r
+  }\r
+  \r
   return Status;\r
 }\r
 \r
+/**\r
+  Build the FRAMEWORK_EFI_IFR_DATA_ARRAY which will be used to pass to \r
+  EFI_FORM_CALLBACK_PROTOCOL.Callback. Check definition of FRAMEWORK_EFI_IFR_DATA_ARRAY\r
+  for details.\r
+\r
+  ASSERT if the Question Type is not EFI_IFR_TYPE_NUM_SIZE_* or EFI_IFR_TYPE_STRING.\r
+  \r
+   @param This             Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL\r
+   @param QuestionId       The Question ID.\r
+   @param Type             The Question Type.\r
+   @param Value            The Question Value.\r
+   @param NvMapAllocated   On output indicates if a buffer is allocated for NvMap.\r
+   \r
+   @return A pointer to FRAMEWORK_EFI_IFR_DATA_ARRAY. The caller must free this buffer allocated.\r
+**/   \r
+FRAMEWORK_EFI_IFR_DATA_ARRAY *\r
+CreateIfrDataArray (\r
+  IN    CONFIG_ACCESS_PRIVATE         *ConfigAccess,\r
+  IN    EFI_QUESTION_ID               QuestionId,\r
+  IN    UINT8                         Type,\r
+  IN    EFI_IFR_TYPE_VALUE            *Value,\r
+  OUT   BOOLEAN                       *NvMapAllocated\r
+  )\r
+{\r
+  FRAMEWORK_EFI_IFR_DATA_ARRAY      *IfrDataArray;\r
+  FRAMEWORK_EFI_IFR_DATA_ENTRY      *IfrDataEntry;\r
+  UINTN                             BrowserDataSize;\r
+  FORMSET_STORAGE                  *BufferStorage;\r
+  EFI_STATUS                        Status;\r
+  UINTN                             Size;\r
+  UINTN                             StringSize;\r
+  EFI_STRING                        String;\r
+\r
+  *NvMapAllocated = FALSE;\r
+\r
+  String = NULL;\r
+\r
+  switch (Type) {\r
+    case EFI_IFR_TYPE_NUM_SIZE_8:\r
+    case EFI_IFR_TYPE_NUM_SIZE_16:\r
+    case EFI_IFR_TYPE_NUM_SIZE_32:\r
+    case EFI_IFR_TYPE_NUM_SIZE_64:\r
+    case EFI_IFR_TYPE_BOOLEAN:\r
+      Size = sizeof (*Value);\r
+      break;\r
+\r
+    case EFI_IFR_TYPE_STRING:\r
+      StringSize = 0;\r
+      Status = HiiLibGetString (ConfigAccess->ThunkContext->UefiHiiHandle, Value->string, String, &StringSize);\r
+      ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
+\r
+      String = AllocateZeroPool (StringSize);\r
+      ASSERT (String != NULL);\r
+\r
+      Status = HiiLibGetString (ConfigAccess->ThunkContext->UefiHiiHandle, Value->string, String, &StringSize);\r
+      ASSERT_EFI_ERROR (Status);\r
+\r
+      Size = StringSize;\r
+      break;\r
+      \r
+    default:\r
+      ASSERT (FALSE);\r
+      Size = 0;\r
+      break;\r
+  }\r
+\r
+  IfrDataArray = AllocateZeroPool (sizeof (FRAMEWORK_EFI_IFR_DATA_ARRAY) + sizeof (FRAMEWORK_EFI_IFR_DATA_ENTRY) + Size);\r
+  ASSERT (IfrDataArray != NULL);\r
+\r
+  BufferStorage  = GetStorageFromQuestionId (ConfigAccess->ThunkContext->FormSet, QuestionId);\r
+\r
+  if (BufferStorage == NULL) {\r
+    //\r
+    // The QuestionId is not associated with a Buffer Storage.\r
+    // Try to get the first Buffer Storage then.\r
+    //\r
+    BufferStorage = GetFirstStorageOfFormSet (ConfigAccess->ThunkContext->FormSet);\r
+  }\r
+  \r
+  if (BufferStorage != NULL) {\r
+    BrowserDataSize = BufferStorage->Size;\r
+\r
+    if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
+      *NvMapAllocated = TRUE;\r
+      IfrDataArray->NvRamMap = AllocateZeroPool (BrowserDataSize);\r
+    } else {\r
+      *NvMapAllocated = FALSE;\r
+      IfrDataArray->NvRamMap = ConfigAccess->ThunkContext->NvMapOverride;\r
+    }\r
+    \r
+    Status = GetBrowserData (&BufferStorage->Guid, BufferStorage->Name, &BrowserDataSize, IfrDataArray->NvRamMap);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    IfrDataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) (IfrDataArray + 1);\r
+\r
+    switch (Type) {\r
+      case EFI_IFR_TYPE_NUM_SIZE_8:\r
+      case EFI_IFR_TYPE_NUM_SIZE_16:\r
+      case EFI_IFR_TYPE_NUM_SIZE_32:\r
+      case EFI_IFR_TYPE_NUM_SIZE_64:\r
+      case EFI_IFR_TYPE_BOOLEAN:\r
+        CopyMem (&IfrDataEntry->Data, &(Value->u8), sizeof (*Value));\r
+        break;\r
+\r
+      case EFI_IFR_TYPE_STRING:\r
+        ASSERT (String != NULL);\r
+        StrCpy ((CHAR16 *) &IfrDataEntry->Data, String);\r
+        FreePool (String);\r
+        break;\r
+      default:\r
+        ASSERT (FALSE);\r
+        break;\r
+    }\r
+\r
+    //\r
+    // Need to fiil in the information for the rest of field for FRAMEWORK_EFI_IFR_DATA_ENTRY.\r
+    // It seems that no implementation is found to use other fields. Leave them uninitialized for now.\r
+    //\r
+    //UINT8   OpCode;           // Likely a string, numeric, or one-of\r
+    //UINT8   Length;           // Length of the FRAMEWORK_EFI_IFR_DATA_ENTRY packet\r
+    //UINT16  Flags;            // Flags settings to determine what behavior is desired from the browser after the callback\r
+    //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
+    // If the OpCode is a OneOf or Numeric type - Data is a UINT16 value\r
+    // If the OpCode is a String type - Data is a CHAR16[x] type\r
+    // If the OpCode is a Checkbox type - Data is a UINT8 value\r
+    // If the OpCode is a NV Access type - Data is a FRAMEWORK_EFI_IFR_NV_DATA structure\r
+  }\r
+\r
+  return IfrDataArray;\r
+}\r
+\r
+/**\r
+  If a NvMapOverride is passed in to EFI_FORM_BROWSER_PROTOCOL.SendForm, the Form Browser\r
+  needs to be informed when data changed in NvMapOverride. This function will invoke\r
+  SetBrowserData () to set internal data of Form Browser.\r
+\r
+  @param  ConfigAccess   The Config Access Private Context.\r
+  @param  QuestionId     The Question Id that invokes the callback.\r
+  \r
+\r
+**/\r
+VOID\r
+SyncBrowserDataForNvMapOverride (\r
+  IN    CONST CONFIG_ACCESS_PRIVATE         *ConfigAccess,\r
+  IN          EFI_QUESTION_ID               QuestionId\r
+  )\r
+{\r
+  FORMSET_STORAGE                  *BufferStorage;\r
+  EFI_STATUS                        Status;\r
+  UINTN                             BrowserDataSize;\r
+\r
+  if (ConfigAccess->ThunkContext->NvMapOverride != NULL) {\r
+\r
+    BufferStorage = GetStorageFromQuestionId (ConfigAccess->ThunkContext->FormSet, QuestionId);\r
+\r
+    if (BufferStorage == NULL) {\r
+      //\r
+      // QuestionId is a statement without Storage.\r
+      // 1) It is a Goto. \r
+      // \r
+      //\r
+      BufferStorage = GetFirstStorageOfFormSet (ConfigAccess->ThunkContext->FormSet);\r
+    }\r
+\r
+    //\r
+    // If NvMapOverride is not NULL, this Form must have at least one Buffer Type Variable Storage.\r
+    //\r
+    ASSERT (BufferStorage != NULL);\r
+    \r
+    BrowserDataSize = BufferStorage->Size;\r
+\r
+    Status = SetBrowserData (&BufferStorage->Guid, BufferStorage->Name, BrowserDataSize, ConfigAccess->ThunkContext->NvMapOverride, NULL);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+}\r
+\r
+/**\r
+  Free up resource allocated for a FRAMEWORK_EFI_IFR_DATA_ARRAY by CreateIfrDataArray ().\r
+\r
+  @param Array              The FRAMEWORK_EFI_IFR_DATA_ARRAY allocated.\r
+  @param NvMapAllocated     If the NvRamMap is allocated for FRAMEWORK_EFI_IFR_DATA_ARRAY.\r
+\r
+**/\r
+VOID\r
+DestroyIfrDataArray (\r
+  IN  FRAMEWORK_EFI_IFR_DATA_ARRAY *Array,\r
+  IN  BOOLEAN                      NvMapAllocated\r
+  )\r
+{\r
+  if (Array != NULL) {\r
+    if (NvMapAllocated) {\r
+      FreePool (Array->NvRamMap);\r
+    }\r
+\r
+    FreePool (Array);\r
+  }\r
+}\r
+\r
+/**\r
+  Get the ONE_OF_OPTION_MAP_ENTRY for a QuestionId that invokes the \r
+  EFI_FORM_CALLBACK_PROTOCOL.Callback. The information is needed as\r
+  the callback mechanism for EFI_IFR_ONE_OF_OPTION is changed from \r
+  EFI_IFR_ONE_OF_OPTION in Framework IFR. Check EFI_IFR_GUID_OPTIONKEY\r
+  for detailed information.\r
+\r
+  @param ThunkContext   The Thunk Context.\r
+  @param QuestionId     The Question Id.\r
+  @param Type           The Question Type.\r
+  @param Value          The One Of Option's value.\r
+\r
+  @return The ONE_OF_OPTION_MAP_ENTRY found.\r
+  @retval NULL If no entry is found.\r
+**/\r
+ONE_OF_OPTION_MAP_ENTRY *\r
+GetOneOfOptionMapEntry (\r
+  IN  HII_THUNK_CONTEXT              *ThunkContext,\r
+  IN  EFI_QUESTION_ID                QuestionId,\r
+  IN  UINT8                          Type,\r
+  IN  EFI_IFR_TYPE_VALUE             *Value\r
+  )\r
+{\r
+  LIST_ENTRY              *Link;\r
+  LIST_ENTRY              *Link2;\r
+  ONE_OF_OPTION_MAP_ENTRY *OneOfOptionMapEntry;\r
+  ONE_OF_OPTION_MAP       *OneOfOptionMap;\r
+  FORM_BROWSER_FORMSET    *FormSet;\r
+\r
+  FormSet = ThunkContext->FormSet;\r
+\r
+  Link = GetFirstNode (&FormSet->OneOfOptionMapListHead);\r
+\r
+  while (!IsNull (&FormSet->OneOfOptionMapListHead, Link)) {\r
+    OneOfOptionMap = ONE_OF_OPTION_MAP_FROM_LINK(Link);\r
+    if (OneOfOptionMap->QuestionId == QuestionId) {\r
+      ASSERT (OneOfOptionMap->ValueType == Type);\r
+\r
+      Link2 = GetFirstNode (&OneOfOptionMap->OneOfOptionMapEntryListHead);\r
+\r
+      while (!IsNull (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2)) {\r
+        OneOfOptionMapEntry = ONE_OF_OPTION_MAP_ENTRY_FROM_LINK (Link2);\r
+\r
+        if (CompareMem (Value, &OneOfOptionMapEntry->Value, sizeof (EFI_IFR_TYPE_VALUE)) == 0) {\r
+          return OneOfOptionMapEntry;\r
+        }\r
+\r
+        Link2 = GetNextNode (&OneOfOptionMap->OneOfOptionMapEntryListHead, Link2);\r
+      }\r
+    }\r
+\r
+    Link = GetNextNode (&FormSet->OneOfOptionMapListHead, Link);\r
+  }\r
+\r
+\r
+  return NULL;\r
+}\r
+\r
+/**\r
+  Functions which are registered to receive notification of\r
+  database events have this prototype. The actual event is encoded\r
+  in NotifyType. The following table describes how PackageType,\r
+  PackageGuid, Handle, and Package are used for each of the\r
+  notification types.\r
+\r
+  If any Pakcage List in database is updated, mHiiPackageListUpdated\r
+  will be set. If mHiiPackageListUpdated is set, Framework ThunkCallback()\r
+  will force the UEFI Setup Browser to save the uncommitted data. This\r
+  is needed as Framework's Callback function may dynamically update\r
+  opcode in a Package List. UEFI Setup Browser will quit itself and reparse\r
+  the Package List's IFR and display it. UEFI Config Access's implementation\r
+  is required to save the modified (SetBrowserData or directly save the data\r
+  to NV storage). But Framework HII Modules is not aware of this rule. Therefore,\r
+  we will enforce the rule in ThunkCallback (). The side effect of force saving\r
+  of NV data is the NV flag in browser may not flag a update as data has already\r
+  been saved to NV storage.\r
+\r
+  @param PackageType  Package type of the notification.\r
+\r
+  @param PackageGuid  If PackageType is\r
+                      EFI_HII_PACKAGE_TYPE_GUID, then this is\r
+                      the pointer to the GUID from the Guid\r
+                      field of EFI_HII_PACKAGE_GUID_HEADER.\r
+                      Otherwise, it must be NULL.\r
+\r
+  @param Package  Points to the package referred to by the\r
+                  notification Handle The handle of the package\r
+                  list which contains the specified package.\r
+\r
+  @param Handle       The HII handle.\r
+\r
+  @param NotifyType   The type of change concerning the\r
+                      database. See\r
+                      EFI_HII_DATABASE_NOTIFY_TYPE.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FormUpdateNotify (\r
+  IN UINT8                              PackageType,\r
+  IN CONST EFI_GUID                     *PackageGuid,\r
+  IN CONST EFI_HII_PACKAGE_HEADER       *Package,\r
+  IN EFI_HII_HANDLE                     Handle,\r
+  IN EFI_HII_DATABASE_NOTIFY_TYPE       NotifyType\r
+  )\r
+{\r
+  mHiiPackageListUpdated = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Wrap the EFI_HII_CONFIG_ACCESS_PROTOCOL.CallBack to EFI_FORM_CALLBACK_PROTOCOL.Callback. Therefor,\r
-  the framework HII module willl do no porting (except some porting works needed for callback for EFI_ONE_OF_OPTION opcode)\r
-  and still work with a UEFI HII SetupBrowser.\r
+  the framework HII module willl do no porting and work with a UEFI HII SetupBrowser.\r
    \r
-   @param This                          Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
-   @param Action                       Specifies the type of action taken by the browser. See EFI_BROWSER_ACTION_x.\r
+   @param This                      Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+   @param Action                    Specifies the type of action taken by the browser. See EFI_BROWSER_ACTION_x.\r
    @param QuestionId                A unique value which is sent to the original exporting driver so that it can identify the\r
-                                                type of data to expect. The format of the data tends to vary based on the opcode that\r
-                                                generated the callback.\r
-   @param Type                         The type of value for the question. See EFI_IFR_TYPE_x in\r
-                                                EFI_IFR_ONE_OF_OPTION.\r
-   @param Value                        A pointer to the data being sent to the original exporting driver. The type is specified\r
-                                                by Type. Type EFI_IFR_TYPE_VALUE is defined in\r
-                                                EFI_IFR_ONE_OF_OPTION.\r
+                                    type of data to expect. The format of the data tends to vary based on the opcode that\r
+                                    generated the callback.\r
+   @param Type                      The type of value for the question. See EFI_IFR_TYPE_x in\r
+                                    EFI_IFR_ONE_OF_OPTION.\r
+   @param Value                     A pointer to the data being sent to the original exporting driver. The type is specified\r
+                                    by Type. Type EFI_IFR_TYPE_VALUE is defined in\r
+                                    EFI_IFR_ONE_OF_OPTION.\r
    @param ActionRequest             On return, points to the action requested by the callback function. Type\r
-                                                EFI_BROWSER_ACTION_REQUEST is specified in SendForm() in the Form\r
-                                                Browser Protocol.\r
+                                    EFI_BROWSER_ACTION_REQUEST is specified in SendForm() in the Form\r
+                                    Browser Protocol.\r
    \r
-   @retval EFI_UNSUPPORTED      If the Framework HII module does not register Callback although it specify the opcode under\r
-                                                focuse to be INTERRACTIVE.\r
+   @retval EFI_UNSUPPORTED        If the Framework HII module does not register Callback although it specify the opcode under\r
+                                  focuse to be INTERRACTIVE.\r
    @retval EFI_SUCCESS            The callback complete successfully.\r
    @retval !EFI_SUCCESS           The error code returned by EFI_FORM_CALLBACK_PROTOCOL.Callback.\r
    \r
@@ -594,12 +918,16 @@ ThunkCallback (
   )\r
 {\r
   EFI_STATUS                                  Status;\r
-  HII_TRHUNK_CONFIG_ACCESS_PROTOCOL_INSTANCE  *ConfigaAccessInstance;\r
-  EFI_FORM_CALLBACK_PROTOCOL                  *FrameworkFormCallbackProtocol;\r
+  CONFIG_ACCESS_PRIVATE                       *ConfigAccess;\r
+  EFI_FORM_CALLBACK_PROTOCOL                  *FormCallbackProtocol;\r
   EFI_HII_CALLBACK_PACKET                     *Packet;\r
-  FRAMEWORK_EFI_IFR_DATA_ARRAY                Data;\r
+  FRAMEWORK_EFI_IFR_DATA_ARRAY                *Data;\r
   FRAMEWORK_EFI_IFR_DATA_ENTRY                *DataEntry;\r
-  EFI_FORM_CALLBACK                           Callback; \r
+  UINT16                                      KeyValue;\r
+  ONE_OF_OPTION_MAP_ENTRY                     *OneOfOptionMapEntry;\r
+  EFI_HANDLE                                  NotifyHandle;\r
+  EFI_INPUT_KEY                               Key;  \r
+  BOOLEAN                                     NvMapAllocated;\r
 \r
   ASSERT (This != NULL);\r
   ASSERT (Value != NULL);\r
@@ -607,43 +935,118 @@ ThunkCallback (
 \r
   *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
 \r
-  ConfigaAccessInstance = HII_TRHUNK_CONFIG_ACCESS_PROTOCOL_INSTANCE_FROM_PROTOCOL (This);\r
+  ConfigAccess = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (This);\r
 \r
-  FrameworkFormCallbackProtocol = ConfigaAccessInstance->FrameworkFormCallbackProtocol;\r
-  if (FrameworkFormCallbackProtocol == NULL) {\r
+  FormCallbackProtocol = ConfigAccess->FormCallbackProtocol;\r
+  if (FormCallbackProtocol == NULL) {\r
+    ASSERT (FALSE);\r
     return EFI_UNSUPPORTED;\r
   }\r
-  Callback = FrameworkFormCallbackProtocol->Callback;\r
 \r
-  Status = Callback (\r
-              FrameworkFormCallbackProtocol,\r
-              QuestionId,\r
-              &Data,\r
+  //\r
+  // Check if the QuestionId match a OneOfOption.\r
+  //\r
+  OneOfOptionMapEntry = GetOneOfOptionMapEntry (ConfigAccess->ThunkContext, QuestionId, Type, Value);\r
+\r
+  if (OneOfOptionMapEntry == NULL) {\r
+    //\r
+    // This is not a One-Of-Option opcode. QuestionId is the KeyValue\r
+    //\r
+    KeyValue = QuestionId;\r
+  } else {\r
+    //\r
+    // Otherwise, use the original Key specified in One Of Option in the Framework VFR syntax.\r
+    //\r
+    KeyValue = OneOfOptionMapEntry->FwKey;\r
+  }\r
+\r
+  //\r
+  // Build the FRAMEWORK_EFI_IFR_DATA_ARRAY\r
+  //\r
+  Data = CreateIfrDataArray (ConfigAccess, QuestionId, Type, Value, &NvMapAllocated);\r
+\r
+  Status = mHiiDatabase->RegisterPackageNotify (\r
+                           mHiiDatabase,\r
+                           EFI_HII_PACKAGE_FORMS,\r
+                           NULL,\r
+                           FormUpdateNotify,\r
+                           EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,\r
+                           &NotifyHandle\r
+                           );\r
+  //\r
+  //Call the Framework Callback function.\r
+  //\r
+  Packet =  NULL;\r
+  Status =  FormCallbackProtocol->Callback (\r
+              FormCallbackProtocol,\r
+              KeyValue,\r
+              Data,\r
               &Packet\r
               );\r
+  SyncBrowserDataForNvMapOverride (ConfigAccess, QuestionId);\r
 \r
   //\r
   // Callback require browser to perform action\r
   //\r
-  if (Packet != NULL) {\r
-    if (Packet->DataArray.EntryCount  == 1 && Packet->DataArray.NvRamMap == NULL) {\r
-      DataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) ((UINT8 *) Packet + sizeof (FRAMEWORK_EFI_IFR_DATA_ARRAY));\r
-      switch (DataEntry->Flags) {\r
-        case EXIT_REQUIRED:\r
-          *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
-          break;\r
-        case SAVE_REQUIRED:\r
-          *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
-          break;\r
-        case RESET_REQUIRED:\r
-            *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET;\r
-            break;\r
-        default:\r
-            *ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;\r
-            break;  \r
-      }\r
+  if (EFI_ERROR (Status)) {\r
+    if (Packet != NULL) {\r
+      do {\r
+        IfrLibCreatePopUp (1, &Key, Packet->String);\r
+      } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
+    }\r
+    //\r
+    // Error Code in Status is discarded.\r
+    //\r
+  } else {\r
+    if (Packet != NULL) {\r
+        if (Packet->DataArray.EntryCount  == 1 && Packet->DataArray.NvRamMap == NULL) {\r
+          DataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) ((UINT8 *) Packet + sizeof (FRAMEWORK_EFI_IFR_DATA_ARRAY));\r
+          if ((DataEntry->Flags & EXIT_REQUIRED) == EXIT_REQUIRED) {\r
+              *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
+          }\r
+\r
+          if ((DataEntry->Flags & SAVE_REQUIRED) == SAVE_REQUIRED) {\r
+            Status = ConfigAccess->ConfigAccessProtocol.RouteConfig (\r
+                                      &ConfigAccess->ConfigAccessProtocol,\r
+                                      NULL,\r
+                                      NULL\r
+                                      );\r
+          }\r
+        }\r
+        FreePool (Packet);\r
     }\r
   }\r
+\r
+  //\r
+  // Unregister notify for Form package update\r
+  //\r
+  Status = mHiiDatabase->UnregisterPackageNotify (\r
+                           mHiiDatabase,\r
+                           NotifyHandle\r
+                           );\r
+  //\r
+  // UEFI SetupBrowser behaves differently with Framework SetupBrowser when call back function \r
+  // update any forms in HII database. UEFI SetupBrowser will re-parse the displaying form package and load\r
+  // the values from variable storages. Framework SetupBrowser will only re-parse the displaying form packages.\r
+  // To make sure customer's previous changes is saved and the changing question behaves as expected, we\r
+  // issue a EFI_BROWSER_ACTION_REQUEST_SUBMIT to ask UEFI SetupBrowser to save the changes proceed to re-parse\r
+  // the form and load all the variable storages.\r
+  //\r
+  if (*ActionRequest == EFI_BROWSER_ACTION_REQUEST_NONE && mHiiPackageListUpdated) {\r
+    mHiiPackageListUpdated= FALSE;\r
+    *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+  } else {\r
+    if (ConfigAccess->ThunkContext->FormSet->SubClass == EFI_FRONT_PAGE_SUBCLASS ||\r
+        ConfigAccess->ThunkContext->FormSet->SubClass == EFI_SINGLE_USE_SUBCLASS) {\r
+      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;\r
+    }\r
+  }\r
+\r
+\r
+  //\r
+  // Clean up.\r
+  //\r
+  DestroyIfrDataArray (Data, NvMapAllocated);\r
   \r
   return Status;\r
 }\r