]> 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 c537a47b1ce9c5c43277a6f9bfcb701191d91b17..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,8 +15,9 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 **/\r
 \r
 #include "HiiDatabase.h"\r
+#include "UefiIfrParser.h"\r
 \r
-BOOLEAN            mHiiPackageListUpdated;\r
+BOOLEAN            mHiiPackageListUpdated = FALSE;\r
 \r
 CONFIG_ACCESS_PRIVATE gConfigAccessPrivateTempate = {\r
   CONFIG_ACCESS_PRIVATE_SIGNATURE,\r
@@ -26,154 +27,157 @@ CONFIG_ACCESS_PRIVATE gConfigAccessPrivateTempate = {
     ThunkCallback\r
   }, //ConfigAccessProtocol\r
   NULL, //FormCallbackProtocol\r
-  {NULL, NULL}, //ConfigAccessStorageListHead\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 Packages                  The Framework Package List\r
+  @param FormSet                  The Form Set.\r
    \r
-   @retval EFI_HII_PACKAGE_HEADER* Return the Package Header of Form Package.\r
-   @retval NULL                    If no Form Package is found.\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
-EFI_HII_PACKAGE_HEADER *\r
-GetIfrFormSet (\r
-  IN  CONST EFI_HII_PACKAGES  *Packages\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 FormSet                  The Form Set.\r
+   \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
+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 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
-  BUFFER_STORAGE_ENTRY *BufferStorage;\r
-\r
-  ASSERT (FormSetPackage->Type == EFI_HII_PACKAGE_FORM);\r
-\r
-  OpCodeOffset = sizeof (EFI_HII_PACKAGE_HEADER);\r
-  //\r
-  // Scan all opcode for the FormSet Package for \r
-  // EFI_IFR_VARSTORE_OP opcode.\r
-  //\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
-      BufferStorage = AllocateZeroPool (sizeof (*BufferStorage));\r
-      if (BufferStorage == NULL) {\r
-        return EFI_OUT_OF_RESOURCES;\r
-      }\r
-      //\r
-      // Record the attributes: GUID, Name, VarStoreId and Size.\r
-      //\r
-      CopyMem (&BufferStorage->Guid, &VarStoreOpCode->Guid, sizeof (EFI_GUID));\r
-      \r
-      BufferStorage->Name = AllocateZeroPool (AsciiStrSize (VarStoreOpCode->Name) * 2);\r
-      AsciiStrToUnicodeStr (VarStoreOpCode->Name, BufferStorage->Name);\r
+  LIST_ENTRY             *StorageList;\r
+  FORMSET_STORAGE        *Storage;\r
 \r
-      BufferStorage->VarStoreId = VarStoreOpCode->VarStoreId;\r
+  StorageList = GetFirstNode (&FormSet->StorageListHead);\r
 \r
-      BufferStorage->Size = VarStoreOpCode->Size;\r
-      BufferStorage->Signature = BUFFER_STORAGE_ENTRY_SIGNATURE;\r
+  while (!IsNull (&FormSet->StorageListHead, StorageList)) {\r
+    Storage = FORMSET_STORAGE_FROM_LINK (StorageList);\r
 \r
-      InsertTailList (BufferStorageListHead, &BufferStorage->Link);\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 ThunkContext             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
@@ -182,73 +186,42 @@ InstallDefaultConfigAccessProtocol (
   IN  OUT   HII_THUNK_CONTEXT                   *ThunkContext\r
   )\r
 {\r
-  EFI_HII_PACKAGE_HEADER                      *FormSetPackage;\r
   EFI_STATUS                                  Status;\r
   CONFIG_ACCESS_PRIVATE                       *ConfigAccessInstance;\r
 \r
+  ASSERT (ThunkContext->IfrPackageCount != 0);\r
+\r
   Status = HiiLibCreateHiiDriverHandle (&ThunkContext->UefiHiiDriverHandle);\r
+  ASSERT_EFI_ERROR (Status);\r
+  \r
   ConfigAccessInstance = AllocateCopyPool (\r
                            sizeof (CONFIG_ACCESS_PRIVATE), \r
                            &gConfigAccessPrivateTempate\r
                            );\r
   ASSERT (ConfigAccessInstance != NULL);\r
   \r
-  InitializeListHead (&ConfigAccessInstance->BufferStorageListHead);\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->BufferStorageListHead);\r
-  if (EFI_ERROR (Status)) {\r
-    FreePool (ConfigAccessInstance);\r
-    ASSERT (FALSE);\r
-    return Status;\r
-  }\r
-\r
   Status = gBS->InstallMultipleProtocolInterfaces (\r
           &ThunkContext->UefiHiiDriverHandle,\r
           &gEfiHiiConfigAccessProtocolGuid,\r
           &ConfigAccessInstance->ConfigAccessProtocol,\r
           NULL\r
           );\r
-  //\r
-  //BUGBUG: Remove when done.\r
-  //\r
   ASSERT_EFI_ERROR (Status);\r
   \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
-VOID\r
-DestroyBufferStorageList (\r
-  IN      LIST_ENTRY  *ListHead\r
-  )\r
-{\r
-  LIST_ENTRY              *Link;\r
-  BUFFER_STORAGE_ENTRY    *Entry;\r
-\r
-  while (!IsListEmpty (ListHead)) {\r
-    Link = GetFirstNode (ListHead);\r
-    \r
-    Entry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link);\r
-\r
-    FreePool (Entry->Name);\r
-    Link = RemoveEntryList (Link);\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
-    FreePool (Entry);\r
-  }\r
-}\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
+**/\r
 VOID\r
 UninstallDefaultConfigAccessProtocol (\r
   IN  HII_THUNK_CONTEXT                   *ThunkContext\r
@@ -256,7 +229,6 @@ UninstallDefaultConfigAccessProtocol (
 {\r
   EFI_STATUS                      Status;\r
   EFI_HII_CONFIG_ACCESS_PROTOCOL  *ConfigAccess;\r
-  CONFIG_ACCESS_PRIVATE           *ConfigAccessInstance;\r
   \r
   HiiLibDestroyHiiDriverHandle (ThunkContext->UefiHiiDriverHandle);\r
 \r
@@ -265,7 +237,6 @@ UninstallDefaultConfigAccessProtocol (
                   &gEfiHiiConfigAccessProtocolGuid,\r
                   (VOID **) &ConfigAccess\r
                   );\r
-\r
   ASSERT_EFI_ERROR (Status);\r
 \r
   Status = gBS->UninstallProtocolInterface (\r
@@ -275,10 +246,6 @@ UninstallDefaultConfigAccessProtocol (
                   );\r
   ASSERT_EFI_ERROR (Status);\r
 \r
-  ConfigAccessInstance = CONFIG_ACCESS_PRIVATE_FROM_PROTOCOL (ConfigAccess);\r
-\r
-  DestroyBufferStorageList (&ConfigAccessInstance->BufferStorageListHead);\r
-\r
 }\r
   \r
 \r
@@ -296,7 +263,7 @@ UninstallDefaultConfigAccessProtocol (
  **/\r
 EFI_STATUS\r
 CallFormCallBack (\r
-  IN       BUFFER_STORAGE_ENTRY              *BufferStorage,\r
+  IN       FORMSET_STORAGE                            *BufferStorage,\r
   IN       EFI_FORM_CALLBACK_PROTOCOL                 *FwFormCallBack,\r
   OUT      VOID                                       **Data,\r
   OUT      UINTN                                      *DataSize\r
@@ -358,7 +325,7 @@ CallFormCallBack (
 \r
 EFI_STATUS\r
 GetUefiVariable (\r
-  IN       BUFFER_STORAGE_ENTRY              *BufferStorage,\r
+  IN       FORMSET_STORAGE                            *BufferStorage,\r
   OUT      VOID                                       **Data,\r
   OUT      UINTN                                      *DataSize\r
   )\r
@@ -432,26 +399,19 @@ ThunkExtractConfig (
 {\r
   EFI_STATUS                                  Status;\r
   CONFIG_ACCESS_PRIVATE                       *ConfigAccess;\r
-  LIST_ENTRY                                  *Link;\r
-  BUFFER_STORAGE_ENTRY                        *BufferStorage;\r
+  FORMSET_STORAGE                             *BufferStorage;\r
   VOID                                        *Data;\r
   UINTN                                       DataSize;\r
 \r
   Data = NULL;\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
-  Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
-  if (Link == NULL) {\r
-    ASSERT (FALSE);\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
-  \r
-  BufferStorage = BUFFER_STORAGE_ENTRY_FROM_LINK (Link);\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
@@ -468,6 +428,9 @@ ThunkExtractConfig (
                  );\r
     }\r
   } else {\r
+    //\r
+    // Use the NvMapOverride.\r
+    //\r
     DataSize = BufferStorage->Size;\r
     Data = AllocateCopyPool (DataSize, ConfigAccess->ThunkContext->NvMapOverride);\r
     \r
@@ -489,12 +452,13 @@ 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
@@ -519,9 +483,8 @@ ThunkRouteConfig (
 {\r
   EFI_STATUS                                  Status;\r
   CONFIG_ACCESS_PRIVATE                       *ConfigAccess;\r
-  LIST_ENTRY                                  *Link;\r
-  BUFFER_STORAGE_ENTRY                        *BufferStorage;\r
-  UINT8                                       *Data;\r
+  FORMSET_STORAGE                             *BufferStorage;\r
+  VOID                                        *Data;\r
   UINTN                                       DataSize;\r
   UINTN                                       DataSize2;\r
   UINTN                                       LastModifiedByteIndex;\r
@@ -531,16 +494,8 @@ ThunkRouteConfig (
   Data = NULL;\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
-  Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
-  if (Link == NULL) {\r
-    ASSERT (FALSE);\r
-    return EFI_INVALID_PARAMETER;\r
-  }\r
+  BufferStorage = GetStorageFromConfigString (ConfigAccess->ThunkContext->FormSet, Configuration);\r
 \r
-  BufferStorage = BUFFER_STORAGE_ENTRY_FROM_LINK (Link);\r
   DataSize2     = BufferStorage->Size;\r
   if (ConfigAccess->ThunkContext->NvMapOverride == NULL) {\r
     DataAllocated = TRUE;\r
@@ -617,6 +572,21 @@ Done:
   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
@@ -629,31 +599,15 @@ CreateIfrDataArray (
   FRAMEWORK_EFI_IFR_DATA_ARRAY      *IfrDataArray;\r
   FRAMEWORK_EFI_IFR_DATA_ENTRY      *IfrDataEntry;\r
   UINTN                             BrowserDataSize;\r
-  BUFFER_STORAGE_ENTRY              *BufferStorageEntry;\r
-  LIST_ENTRY                        *Link;\r
+  FORMSET_STORAGE                  *BufferStorage;\r
   EFI_STATUS                        Status;\r
+  UINTN                             Size;\r
+  UINTN                             StringSize;\r
+  EFI_STRING                        String;\r
 \r
-  IfrDataArray = AllocateZeroPool (0x100);\r
-  ASSERT (IfrDataArray != NULL);\r
-\r
-  Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
-  ASSERT (!IsNull (&ConfigAccess->BufferStorageListHead, Link));\r
-  \r
-  BufferStorageEntry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link);\r
-  BrowserDataSize = BufferStorageEntry->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 (NULL, NULL, &BrowserDataSize, IfrDataArray->NvRamMap);\r
-  ASSERT_EFI_ERROR (Status);\r
+  *NvMapAllocated = FALSE;\r
 \r
-  IfrDataEntry = (FRAMEWORK_EFI_IFR_DATA_ENTRY *) (IfrDataArray + 1);\r
+  String = NULL;\r
 \r
   switch (Type) {\r
     case EFI_IFR_TYPE_NUM_SIZE_8:\r
@@ -661,55 +615,177 @@ CreateIfrDataArray (
     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
+      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    CONFIG_ACCESS_PRIVATE         *ConfigAccess\r
+  IN    CONST CONFIG_ACCESS_PRIVATE         *ConfigAccess,\r
+  IN          EFI_QUESTION_ID               QuestionId\r
   )\r
 {\r
-  BUFFER_STORAGE_ENTRY              *BufferStorageEntry;\r
-  LIST_ENTRY                        *Link;\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
-    Link = GetFirstNode (&ConfigAccess->BufferStorageListHead);\r
-    ASSERT (!IsNull (&ConfigAccess->BufferStorageListHead, Link));\r
-    \r
-    BufferStorageEntry = BUFFER_STORAGE_ENTRY_FROM_LINK(Link);\r
-    BrowserDataSize = BufferStorageEntry->Size;\r
+    BrowserDataSize = BufferStorage->Size;\r
 \r
-    Status = SetBrowserData (NULL, NULL, BrowserDataSize, ConfigAccess->ThunkContext->NvMapOverride, NULL);\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 (NvMapAllocated) {\r
-    FreePool (Array->NvRamMap);\r
-  }\r
+  if (Array != NULL) {\r
+    if (NvMapAllocated) {\r
+      FreePool (Array->NvRamMap);\r
+    }\r
 \r
-  FreePool (Array);\r
+    FreePool (Array);\r
+  }\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
@@ -722,10 +798,13 @@ GetOneOfOptionMapEntry (
   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 (&ThunkContext->OneOfOptionMapListHead);\r
+  Link = GetFirstNode (&FormSet->OneOfOptionMapListHead);\r
 \r
-  while (!IsNull (&ThunkContext->OneOfOptionMapListHead, Link)) {\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
@@ -743,7 +822,7 @@ GetOneOfOptionMapEntry (
       }\r
     }\r
 \r
-    Link = GetNextNode (&ThunkContext->OneOfOptionMapListHead, Link);\r
+    Link = GetNextNode (&FormSet->OneOfOptionMapListHead, Link);\r
   }\r
 \r
 \r
@@ -757,6 +836,18 @@ GetOneOfOptionMapEntry (
   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
@@ -793,8 +884,7 @@ FormUpdateNotify (
 \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
@@ -864,6 +954,9 @@ ThunkCallback (
     //\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
@@ -874,14 +967,14 @@ ThunkCallback (
 \r
   Status = mHiiDatabase->RegisterPackageNotify (\r
                            mHiiDatabase,\r
-                           EFI_HII_PACKAGE_FORM,\r
+                           EFI_HII_PACKAGE_FORMS,\r
                            NULL,\r
                            FormUpdateNotify,\r
                            EFI_HII_DATABASE_NOTIFY_REMOVE_PACK,\r
                            &NotifyHandle\r
                            );\r
   //\r
-  //\r
+  //Call the Framework Callback function.\r
   //\r
   Packet =  NULL;\r
   Status =  FormCallbackProtocol->Callback (\r
@@ -890,24 +983,17 @@ ThunkCallback (
               Data,\r
               &Packet\r
               );\r
-  SyncBrowserDataForNvMapOverride (ConfigAccess);\r
+  SyncBrowserDataForNvMapOverride (ConfigAccess, QuestionId);\r
 \r
   //\r
   // Callback require browser to perform action\r
   //\r
   if (EFI_ERROR (Status)) {\r
     if (Packet != NULL) {\r
-      //\r
-      // BUGBUG: need to restore the changing question to default value\r
-      //\r
-\r
       do {\r
         IfrLibCreatePopUp (1, &Key, Packet->String);\r
-\r
       } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);\r
-      \r
     }\r
-\r
     //\r
     // Error Code in Status is discarded.\r
     //\r
@@ -939,7 +1025,7 @@ ThunkCallback (
                            NotifyHandle\r
                            );\r
   //\r
-  // UEFI SetupBrowser handles scenario differently with Framework SetupBrowser when call back function \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
@@ -947,9 +1033,19 @@ ThunkCallback (
   // 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