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