Home | History | Annotate | Download | only in PlatformVarCleanupLib
      1 /** @file
      2   Sample platform variable cleanup library implementation.
      3 
      4 Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
      5 This program and the accompanying materials
      6 are licensed and made available under the terms and conditions of the BSD License
      7 which accompanies this distribution.  The full text of the license may be found at
      8 http://opensource.org/licenses/bsd-license.php
      9 
     10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include "PlatVarCleanup.h"
     16 
     17 VAR_ERROR_FLAG              mLastVarErrorFlag = VAR_ERROR_FLAG_NO_ERROR;
     18 EDKII_VAR_CHECK_PROTOCOL    *mVarCheck = NULL;
     19 
     20 ///
     21 /// The flag to indicate whether the platform has left the DXE phase of execution.
     22 ///
     23 BOOLEAN                     mEndOfDxe = FALSE;
     24 
     25 LIST_ENTRY                  mUserVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mUserVariableList);
     26 UINT16                      mUserVariableCount = 0;
     27 UINT16                      mMarkedUserVariableCount = 0;
     28 
     29 EFI_GUID                    mVariableCleanupHiiGuid = VARIABLE_CLEANUP_HII_GUID;
     30 CHAR16                      mVarStoreName[] = L"VariableCleanup";
     31 
     32 HII_VENDOR_DEVICE_PATH      mVarCleanupHiiVendorDevicePath = {
     33   {
     34     {
     35       HARDWARE_DEVICE_PATH,
     36       HW_VENDOR_DP,
     37       {
     38         (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
     39         (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
     40       }
     41     },
     42     VARIABLE_CLEANUP_HII_GUID
     43   },
     44   {
     45     END_DEVICE_PATH_TYPE,
     46     END_ENTIRE_DEVICE_PATH_SUBTYPE,
     47     {
     48       (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),
     49       (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)
     50     }
     51   }
     52 };
     53 
     54 /**
     55   Internal get variable error flag.
     56 
     57   @return   Variable error flag.
     58 
     59 **/
     60 VAR_ERROR_FLAG
     61 InternalGetVarErrorFlag (
     62   VOID
     63   )
     64 {
     65   EFI_STATUS        Status;
     66   UINTN             Size;
     67   VAR_ERROR_FLAG    ErrorFlag;
     68 
     69   Size = sizeof (ErrorFlag);
     70   Status = gRT->GetVariable (
     71                   VAR_ERROR_FLAG_NAME,
     72                   &gEdkiiVarErrorFlagGuid,
     73                   NULL,
     74                   &Size,
     75                   &ErrorFlag
     76                   );
     77   if (EFI_ERROR (Status)) {
     78     DEBUG ((EFI_D_INFO, "%s - not found\n", VAR_ERROR_FLAG_NAME));
     79     return VAR_ERROR_FLAG_NO_ERROR;
     80   }
     81   return ErrorFlag;
     82 }
     83 
     84 /**
     85   Is user variable?
     86 
     87   @param[in] Name   Pointer to variable name.
     88   @param[in] Guid   Pointer to vendor guid.
     89 
     90   @retval TRUE      User variable.
     91   @retval FALSE     System variable.
     92 
     93 **/
     94 BOOLEAN
     95 IsUserVariable (
     96   IN CHAR16                     *Name,
     97   IN EFI_GUID                   *Guid
     98   )
     99 {
    100   EFI_STATUS                    Status;
    101   VAR_CHECK_VARIABLE_PROPERTY   Property;
    102 
    103   if (mVarCheck == NULL) {
    104     gBS->LocateProtocol (
    105            &gEdkiiVarCheckProtocolGuid,
    106            NULL,
    107            (VOID **) &mVarCheck
    108            );
    109   }
    110   ASSERT (mVarCheck != NULL);
    111 
    112   ZeroMem (&Property, sizeof (Property));
    113   Status = mVarCheck->VariablePropertyGet (
    114                         Name,
    115                         Guid,
    116                         &Property
    117                         );
    118   if (EFI_ERROR (Status)) {
    119     //
    120     // No property, it is user variable.
    121     //
    122     DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable: %g:%s\n", Guid, Name));
    123     return TRUE;
    124   }
    125 
    126 //  DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Variable Property: %g:%s\n", Guid, Name));
    127 //  DEBUG ((EFI_D_INFO, "  Revision  - 0x%04x\n", Property.Revision));
    128 //  DEBUG ((EFI_D_INFO, "  Property  - 0x%04x\n", Property.Property));
    129 //  DEBUG ((EFI_D_INFO, "  Attribute - 0x%08x\n", Property.Attributes));
    130 //  DEBUG ((EFI_D_INFO, "  MinSize   - 0x%x\n", Property.MinSize));
    131 //  DEBUG ((EFI_D_INFO, "  MaxSize   - 0x%x\n", Property.MaxSize));
    132 
    133   return FALSE;
    134 }
    135 
    136 /**
    137   Find user variable node by variable GUID.
    138 
    139   @param[in] Guid   Pointer to vendor guid.
    140 
    141   @return Pointer to user variable node.
    142 
    143 **/
    144 USER_VARIABLE_NODE *
    145 FindUserVariableNodeByGuid (
    146   IN EFI_GUID   *Guid
    147   )
    148 {
    149   USER_VARIABLE_NODE    *UserVariableNode;
    150   LIST_ENTRY            *Link;
    151 
    152   for (Link = mUserVariableList.ForwardLink
    153        ;Link != &mUserVariableList
    154        ;Link = Link->ForwardLink) {
    155     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
    156 
    157     if (CompareGuid (Guid, &UserVariableNode->Guid)) {
    158       //
    159       // Found it.
    160       //
    161       return UserVariableNode;
    162     }
    163   }
    164 
    165   //
    166   // Create new one if not found.
    167   //
    168   UserVariableNode = AllocateZeroPool (sizeof (*UserVariableNode));
    169   ASSERT (UserVariableNode != NULL);
    170   UserVariableNode->Signature = USER_VARIABLE_NODE_SIGNATURE;
    171   CopyGuid (&UserVariableNode->Guid, Guid);
    172   //
    173   // (36 chars of "########-####-####-####-############" + 1 space + 1 terminator) * sizeof (CHAR16).
    174   //
    175   UserVariableNode->PromptString = AllocatePool ((36 + 2) * sizeof (CHAR16));
    176   ASSERT (UserVariableNode->PromptString != NULL);
    177   UnicodeSPrint (UserVariableNode->PromptString, (36 + 2) * sizeof (CHAR16), L" %g", &UserVariableNode->Guid);
    178   InitializeListHead (&UserVariableNode->NameLink);
    179   InsertTailList (&mUserVariableList, &UserVariableNode->Link);
    180   return UserVariableNode;
    181 }
    182 
    183 /**
    184   Create user variable node.
    185 
    186 **/
    187 VOID
    188 CreateUserVariableNode (
    189   VOID
    190   )
    191 {
    192   EFI_STATUS                    Status;
    193   EFI_STATUS                    GetVariableStatus;
    194   CHAR16                        *VarName;
    195   UINTN                         MaxVarNameSize;
    196   UINTN                         VarNameSize;
    197   UINTN                         MaxDataSize;
    198   UINTN                         DataSize;
    199   VOID                          *Data;
    200   UINT32                        Attributes;
    201   EFI_GUID                      Guid;
    202   USER_VARIABLE_NODE            *UserVariableNode;
    203   USER_VARIABLE_NAME_NODE       *UserVariableNameNode;
    204   UINT16                        Index;
    205   UINTN                         StringSize;
    206 
    207   //
    208   // Initialize 128 * sizeof (CHAR16) variable name size.
    209   //
    210   MaxVarNameSize = 128 * sizeof (CHAR16);
    211   VarName = AllocateZeroPool (MaxVarNameSize);
    212   ASSERT (VarName != NULL);
    213 
    214   //
    215   // Initialize 0x1000 variable data size.
    216   //
    217   MaxDataSize = 0x1000;
    218   Data = AllocateZeroPool (MaxDataSize);
    219   ASSERT (Data != NULL);
    220 
    221   Index = 0;
    222   do {
    223     VarNameSize = MaxVarNameSize;
    224     Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
    225     if (Status == EFI_BUFFER_TOO_SMALL) {
    226       VarName = ReallocatePool (MaxVarNameSize, VarNameSize, VarName);
    227       ASSERT (VarName != NULL);
    228       MaxVarNameSize = VarNameSize;
    229       Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);
    230     }
    231 
    232     if (!EFI_ERROR (Status)) {
    233       if (IsUserVariable (VarName, &Guid)) {
    234         DataSize = MaxDataSize;
    235         GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
    236         if (GetVariableStatus == EFI_BUFFER_TOO_SMALL) {
    237           Data = ReallocatePool (MaxDataSize, DataSize, Data);
    238           ASSERT (Data != NULL);
    239           MaxDataSize = DataSize;
    240           GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);
    241         }
    242         ASSERT_EFI_ERROR (GetVariableStatus);
    243 
    244         if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
    245           UserVariableNode = FindUserVariableNodeByGuid (&Guid);
    246           ASSERT (UserVariableNode != NULL);
    247 
    248           //
    249           // Different variables that have same variable GUID share same user variable node.
    250           //
    251           UserVariableNameNode = AllocateZeroPool (sizeof (*UserVariableNameNode));
    252           ASSERT (UserVariableNameNode != NULL);
    253           UserVariableNameNode->Signature = USER_VARIABLE_NAME_NODE_SIGNATURE;
    254           UserVariableNameNode->Name = AllocateCopyPool (VarNameSize, VarName);
    255           UserVariableNameNode->Attributes = Attributes;
    256           UserVariableNameNode->DataSize = DataSize;
    257           UserVariableNameNode->Index = Index;
    258           UserVariableNameNode->QuestionId = (EFI_QUESTION_ID) (USER_VARIABLE_QUESTION_ID + Index);
    259           //
    260           // 2 space * sizeof (CHAR16) + StrSize.
    261           //
    262           StringSize = 2 * sizeof (CHAR16) + StrSize (UserVariableNameNode->Name);
    263           UserVariableNameNode->PromptString = AllocatePool (StringSize);
    264           ASSERT (UserVariableNameNode->PromptString != NULL);
    265           UnicodeSPrint (UserVariableNameNode->PromptString, StringSize, L"  %s", UserVariableNameNode->Name);
    266           //
    267           // (33 chars of "Attribtues = 0x and DataSize = 0x" + 1 terminator + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16).
    268           //
    269           StringSize = (33 + 1 + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16);
    270           UserVariableNameNode->HelpString = AllocatePool (StringSize);
    271           ASSERT (UserVariableNameNode->HelpString != NULL);
    272           UnicodeSPrint (UserVariableNameNode->HelpString, StringSize, L"Attribtues = 0x%08x and DataSize = 0x%x", UserVariableNameNode->Attributes, UserVariableNameNode->DataSize);
    273           UserVariableNameNode->Deleted = FALSE;
    274           InsertTailList (&UserVariableNode->NameLink, &UserVariableNameNode->Link);
    275           Index++;
    276         }
    277       }
    278     }
    279   } while (Status != EFI_NOT_FOUND);
    280 
    281   mUserVariableCount = Index;
    282   ASSERT (mUserVariableCount <= MAX_USER_VARIABLE_COUNT);
    283   DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable count: 0x%04x\n", mUserVariableCount));
    284 
    285   FreePool (VarName);
    286   FreePool (Data);
    287 }
    288 
    289 /**
    290   Destroy user variable nodes.
    291 
    292 **/
    293 VOID
    294 DestroyUserVariableNode (
    295   VOID
    296   )
    297 {
    298   USER_VARIABLE_NODE        *UserVariableNode;
    299   LIST_ENTRY                *Link;
    300   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
    301   LIST_ENTRY                *NameLink;
    302 
    303   while (mUserVariableList.ForwardLink != &mUserVariableList) {
    304     Link = mUserVariableList.ForwardLink;
    305     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
    306 
    307     RemoveEntryList (&UserVariableNode->Link);
    308 
    309     while (UserVariableNode->NameLink.ForwardLink != &UserVariableNode->NameLink) {
    310       NameLink = UserVariableNode->NameLink.ForwardLink;
    311       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
    312 
    313       RemoveEntryList (&UserVariableNameNode->Link);
    314 
    315       FreePool (UserVariableNameNode->Name);
    316       FreePool (UserVariableNameNode->PromptString);
    317       FreePool (UserVariableNameNode->HelpString);
    318       FreePool (UserVariableNameNode);
    319     }
    320 
    321     FreePool (UserVariableNode->PromptString);
    322     FreePool (UserVariableNode);
    323   }
    324 }
    325 
    326 /**
    327   Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2
    328   descriptor with the input data. NO authentication is required in this function.
    329 
    330   @param[in, out] DataSize          On input, the size of Data buffer in bytes.
    331                                     On output, the size of data returned in Data
    332                                     buffer in bytes.
    333   @param[in, out] Data              On input, Pointer to data buffer to be wrapped or
    334                                     pointer to NULL to wrap an empty payload.
    335                                     On output, Pointer to the new payload date buffer allocated from pool,
    336                                     it's caller's responsibility to free the memory after using it.
    337 
    338   @retval EFI_SUCCESS               Create time based payload successfully.
    339   @retval EFI_OUT_OF_RESOURCES      There are not enough memory resourses to create time based payload.
    340   @retval EFI_INVALID_PARAMETER     The parameter is invalid.
    341   @retval Others                    Unexpected error happens.
    342 
    343 **/
    344 EFI_STATUS
    345 CreateTimeBasedPayload (
    346   IN OUT UINTN      *DataSize,
    347   IN OUT UINT8      **Data
    348   )
    349 {
    350   EFI_STATUS                        Status;
    351   UINT8                             *NewData;
    352   UINT8                             *Payload;
    353   UINTN                             PayloadSize;
    354   EFI_VARIABLE_AUTHENTICATION_2     *DescriptorData;
    355   UINTN                             DescriptorSize;
    356   EFI_TIME                          Time;
    357 
    358   if (Data == NULL || DataSize == NULL) {
    359     return EFI_INVALID_PARAMETER;
    360   }
    361 
    362   //
    363   // At user physical presence, the variable does not need to be signed but the
    364   // parameters to the SetVariable() call still need to be prepared as authenticated
    365   // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate
    366   // data in it.
    367   //
    368   Payload     = *Data;
    369   PayloadSize = *DataSize;
    370 
    371   DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
    372   NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
    373   if (NewData == NULL) {
    374     return EFI_OUT_OF_RESOURCES;
    375   }
    376 
    377   if ((Payload != NULL) && (PayloadSize != 0)) {
    378     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
    379   }
    380 
    381   DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);
    382 
    383   ZeroMem (&Time, sizeof (EFI_TIME));
    384   Status = gRT->GetTime (&Time, NULL);
    385   if (EFI_ERROR (Status)) {
    386     FreePool (NewData);
    387     return Status;
    388   }
    389   Time.Pad1       = 0;
    390   Time.Nanosecond = 0;
    391   Time.TimeZone   = 0;
    392   Time.Daylight   = 0;
    393   Time.Pad2       = 0;
    394   CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));
    395 
    396   DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);
    397   DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;
    398   DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
    399   CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);
    400 
    401   if (Payload != NULL) {
    402     FreePool (Payload);
    403   }
    404 
    405   *DataSize = DescriptorSize + PayloadSize;
    406   *Data     = NewData;
    407   return EFI_SUCCESS;
    408 }
    409 
    410 /**
    411   Create a counter based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION
    412   descriptor with the input data. NO authentication is required in this function.
    413 
    414   @param[in, out] DataSize          On input, the size of Data buffer in bytes.
    415                                     On output, the size of data returned in Data
    416                                     buffer in bytes.
    417   @param[in, out] Data              On input, Pointer to data buffer to be wrapped or
    418                                     pointer to NULL to wrap an empty payload.
    419                                     On output, Pointer to the new payload date buffer allocated from pool,
    420                                     it's caller's responsibility to free the memory after using it.
    421 
    422   @retval EFI_SUCCESS               Create counter based payload successfully.
    423   @retval EFI_OUT_OF_RESOURCES      There are not enough memory resourses to create time based payload.
    424   @retval EFI_INVALID_PARAMETER     The parameter is invalid.
    425   @retval Others                    Unexpected error happens.
    426 
    427 **/
    428 EFI_STATUS
    429 CreateCounterBasedPayload (
    430   IN OUT UINTN      *DataSize,
    431   IN OUT UINT8      **Data
    432   )
    433 {
    434   EFI_STATUS                        Status;
    435   UINT8                             *NewData;
    436   UINT8                             *Payload;
    437   UINTN                             PayloadSize;
    438   EFI_VARIABLE_AUTHENTICATION       *DescriptorData;
    439   UINTN                             DescriptorSize;
    440   UINT64                            MonotonicCount;
    441 
    442   if (Data == NULL || DataSize == NULL) {
    443     return EFI_INVALID_PARAMETER;
    444   }
    445 
    446   //
    447   // At user physical presence, the variable does not need to be signed but the
    448   // parameters to the SetVariable() call still need to be prepared as authenticated
    449   // variable. So we create EFI_VARIABLE_AUTHENTICATED descriptor without certificate
    450   // data in it.
    451   //
    452   Payload     = *Data;
    453   PayloadSize = *DataSize;
    454 
    455   DescriptorSize = (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION, AuthInfo)) + \
    456                    (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) + \
    457                    sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
    458   NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);
    459   if (NewData == NULL) {
    460     return EFI_OUT_OF_RESOURCES;
    461   }
    462 
    463   if ((Payload != NULL) && (PayloadSize != 0)) {
    464     CopyMem (NewData + DescriptorSize, Payload, PayloadSize);
    465   }
    466 
    467   DescriptorData = (EFI_VARIABLE_AUTHENTICATION *) (NewData);
    468 
    469   Status = gBS->GetNextMonotonicCount (&MonotonicCount);
    470   if (EFI_ERROR (Status)) {
    471     FreePool (NewData);
    472     return Status;
    473   }
    474   DescriptorData->MonotonicCount = MonotonicCount;
    475 
    476   DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);
    477   DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;
    478   DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;
    479   CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid);
    480 
    481   if (Payload != NULL) {
    482     FreePool (Payload);
    483   }
    484 
    485   *DataSize = DescriptorSize + PayloadSize;
    486   *Data     = NewData;
    487   return EFI_SUCCESS;
    488 }
    489 
    490 /**
    491   Delete user variable.
    492 
    493   @param[in] DeleteAll              Delete all user variables.
    494   @param[in] VariableCleanupData    Pointer to variable cleanup data.
    495 
    496 **/
    497 VOID
    498 DeleteUserVariable (
    499   IN BOOLEAN                DeleteAll,
    500   IN VARIABLE_CLEANUP_DATA  *VariableCleanupData OPTIONAL
    501   )
    502 {
    503   EFI_STATUS                Status;
    504   USER_VARIABLE_NODE        *UserVariableNode;
    505   LIST_ENTRY                *Link;
    506   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
    507   LIST_ENTRY                *NameLink;
    508   UINTN                     DataSize;
    509   UINT8                     *Data;
    510 
    511   for (Link = mUserVariableList.ForwardLink
    512        ;Link != &mUserVariableList
    513        ;Link = Link->ForwardLink) {
    514     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
    515 
    516     for (NameLink = UserVariableNode->NameLink.ForwardLink
    517         ;NameLink != &UserVariableNode->NameLink
    518         ;NameLink = NameLink->ForwardLink) {
    519       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
    520 
    521       if (!UserVariableNameNode->Deleted && (DeleteAll || ((VariableCleanupData != NULL) && (VariableCleanupData->UserVariable[UserVariableNameNode->Index] == TRUE)))) {
    522         DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
    523         if ((UserVariableNameNode->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {
    524           DataSize = 0;
    525           Data = NULL;
    526           Status = CreateTimeBasedPayload (&DataSize, &Data);
    527           if (!EFI_ERROR (Status)) {
    528             Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
    529             FreePool (Data);
    530           }
    531         } else if ((UserVariableNameNode->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
    532           DataSize = 0;
    533           Data = NULL;
    534           Status = CreateCounterBasedPayload (&DataSize, &Data);
    535           if (!EFI_ERROR (Status)) {
    536             Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);
    537             FreePool (Data);
    538           }
    539         } else {
    540           Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, 0, 0, NULL);
    541         }
    542         if (!EFI_ERROR (Status)) {
    543           UserVariableNameNode->Deleted = TRUE;
    544         } else {
    545           DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable fail: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));
    546         }
    547       }
    548     }
    549   }
    550 }
    551 
    552 /**
    553   This function allows a caller to extract the current configuration for one
    554   or more named elements from the target driver.
    555 
    556   @param[in]  This          Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    557   @param[in]  Request       A null-terminated Unicode string in <ConfigRequest> format.
    558   @param[out] Progress      On return, points to a character in the Request string.
    559                             Points to the string's null terminator if request was successful.
    560                             Points to the most recent '&' before the first failing name/value
    561                             pair (or the beginning of the string if the failure is in the
    562                             first name/value pair) if the request was not successful.
    563   @param[out] Results       A null-terminated Unicode string in <ConfigAltResp> format which
    564                             has all values filled in for the names in the Request string.
    565                             String to be allocated by the called function.
    566 
    567   @retval EFI_SUCCESS               The Results is filled with the requested values.
    568   @retval EFI_OUT_OF_RESOURCES      Not enough memory to store the results.
    569   @retval EFI_INVALID_PARAMETER     Request is illegal syntax, or unknown name.
    570   @retval EFI_NOT_FOUND             Routing data doesn't match any storage in this driver.
    571 
    572 **/
    573 EFI_STATUS
    574 EFIAPI
    575 VariableCleanupHiiExtractConfig (
    576   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
    577   IN  CONST EFI_STRING                          Request,
    578   OUT EFI_STRING                                *Progress,
    579   OUT EFI_STRING                                *Results
    580   )
    581 {
    582   EFI_STATUS                        Status;
    583   VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
    584   UINTN                             BufferSize;
    585   EFI_STRING                        ConfigRequestHdr;
    586   EFI_STRING                        ConfigRequest;
    587   BOOLEAN                           AllocatedRequest;
    588   UINTN                             Size;
    589 
    590   if (Progress == NULL || Results == NULL) {
    591     return EFI_INVALID_PARAMETER;
    592   }
    593 
    594   *Progress = Request;
    595   if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mVariableCleanupHiiGuid, mVarStoreName)) {
    596     return EFI_NOT_FOUND;
    597   }
    598 
    599   ConfigRequestHdr = NULL;
    600   ConfigRequest    = NULL;
    601   AllocatedRequest = FALSE;
    602   Size             = 0;
    603 
    604   Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
    605   //
    606   // Convert buffer data to <ConfigResp> by helper function BlockToConfig().
    607   //
    608   BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
    609   ConfigRequest = Request;
    610   if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
    611     //
    612     // Request has no request element, construct full request string.
    613     // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
    614     // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.
    615     //
    616     ConfigRequestHdr = HiiConstructConfigHdr (&mVariableCleanupHiiGuid, mVarStoreName, Private->HiiHandle);
    617     Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
    618     ConfigRequest = AllocateZeroPool (Size);
    619     ASSERT (ConfigRequest != NULL);
    620     AllocatedRequest = TRUE;
    621     UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
    622     FreePool (ConfigRequestHdr);
    623   }
    624 
    625   Status = Private->ConfigRouting->BlockToConfig (
    626                                      Private->ConfigRouting,
    627                                      ConfigRequest,
    628                                      (UINT8 *) &Private->VariableCleanupData,
    629                                      BufferSize,
    630                                      Results,
    631                                      Progress
    632                                      );
    633   ASSERT_EFI_ERROR (Status);
    634 
    635   //
    636   // Free the allocated config request string.
    637   //
    638   if (AllocatedRequest) {
    639     FreePool (ConfigRequest);
    640     ConfigRequest = NULL;
    641   }
    642   //
    643   // Set Progress string to the original request string or the string's null terminator.
    644   //
    645   if (Request == NULL) {
    646     *Progress = NULL;
    647   } else if (StrStr (Request, L"OFFSET") == NULL) {
    648     *Progress = Request + StrLen (Request);
    649   }
    650 
    651   return Status;
    652 }
    653 
    654 /**
    655   Update user variable form.
    656 
    657   @param[in] Private    Points to the VARIABLE_CLEANUP_HII_PRIVATE_DATA.
    658 
    659 **/
    660 VOID
    661 UpdateUserVariableForm (
    662   IN VARIABLE_CLEANUP_HII_PRIVATE_DATA  *Private
    663   )
    664 {
    665   EFI_STRING_ID             PromptStringToken;
    666   EFI_STRING_ID             HelpStringToken;
    667   VOID                      *StartOpCodeHandle;
    668   VOID                      *EndOpCodeHandle;
    669   EFI_IFR_GUID_LABEL        *StartLabel;
    670   EFI_IFR_GUID_LABEL        *EndLabel;
    671   USER_VARIABLE_NODE        *UserVariableNode;
    672   LIST_ENTRY                *Link;
    673   USER_VARIABLE_NAME_NODE   *UserVariableNameNode;
    674   LIST_ENTRY                *NameLink;
    675   BOOLEAN                   Created;
    676 
    677   //
    678   // Init OpCode Handle.
    679   //
    680   StartOpCodeHandle = HiiAllocateOpCodeHandle ();
    681   ASSERT (StartOpCodeHandle != NULL);
    682 
    683   EndOpCodeHandle = HiiAllocateOpCodeHandle ();
    684   ASSERT (EndOpCodeHandle != NULL);
    685 
    686   //
    687   // Create Hii Extend Label OpCode as the start opcode.
    688   //
    689   StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    690   StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    691   StartLabel->Number = LABEL_START;
    692 
    693   //
    694   // Create Hii Extend Label OpCode as the end opcode.
    695   //
    696   EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
    697   EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
    698   EndLabel->Number = LABEL_END;
    699 
    700   HiiUpdateForm (
    701     Private->HiiHandle,
    702     &mVariableCleanupHiiGuid,
    703     FORM_ID_VARIABLE_CLEANUP,
    704     StartOpCodeHandle, // LABEL_START
    705     EndOpCodeHandle    // LABEL_END
    706     );
    707 
    708   for (Link = mUserVariableList.ForwardLink
    709       ;Link != &mUserVariableList
    710       ;Link = Link->ForwardLink) {
    711     UserVariableNode = USER_VARIABLE_FROM_LINK (Link);
    712 
    713     //
    714     // Create checkbox opcode for variables in the same variable GUID space.
    715     //
    716     Created = FALSE;
    717     for (NameLink = UserVariableNode->NameLink.ForwardLink
    718         ;NameLink != &UserVariableNode->NameLink
    719         ;NameLink = NameLink->ForwardLink) {
    720       UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);
    721 
    722       if (!UserVariableNameNode->Deleted) {
    723         if (!Created) {
    724           //
    725           // Create subtitle opcode for variable GUID.
    726           //
    727           PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNode->PromptString, NULL);
    728           HiiCreateSubTitleOpCode (StartOpCodeHandle, PromptStringToken, 0, 0, 0);
    729           Created = TRUE;
    730         }
    731 
    732         //
    733         // Only create opcode for the non-deleted variables.
    734         //
    735         PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->PromptString, NULL);
    736         HelpStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->HelpString, NULL);
    737         HiiCreateCheckBoxOpCode (
    738           StartOpCodeHandle,
    739           UserVariableNameNode->QuestionId,
    740           VARIABLE_CLEANUP_VARSTORE_ID,
    741           (UINT16) (USER_VARIABLE_VAR_OFFSET + UserVariableNameNode->Index),
    742           PromptStringToken,
    743           HelpStringToken,
    744           EFI_IFR_FLAG_CALLBACK,
    745           Private->VariableCleanupData.UserVariable[UserVariableNameNode->Index],
    746           NULL
    747           );
    748       }
    749     }
    750   }
    751 
    752   HiiCreateSubTitleOpCode (
    753     StartOpCodeHandle,
    754     STRING_TOKEN (STR_NULL_STRING),
    755     0,
    756     0,
    757     0
    758     );
    759 
    760   //
    761   // Create the "Apply changes" and "Discard changes" tags.
    762   //
    763   HiiCreateActionOpCode (
    764     StartOpCodeHandle,
    765     SAVE_AND_EXIT_QUESTION_ID,
    766     STRING_TOKEN (STR_SAVE_AND_EXIT),
    767     STRING_TOKEN (STR_NULL_STRING),
    768     EFI_IFR_FLAG_CALLBACK,
    769     0
    770     );
    771   HiiCreateActionOpCode (
    772     StartOpCodeHandle,
    773     NO_SAVE_AND_EXIT_QUESTION_ID,
    774     STRING_TOKEN (STR_NO_SAVE_AND_EXIT),
    775     STRING_TOKEN (STR_NULL_STRING),
    776     EFI_IFR_FLAG_CALLBACK,
    777     0
    778     );
    779 
    780   HiiUpdateForm (
    781     Private->HiiHandle,
    782     &mVariableCleanupHiiGuid,
    783     FORM_ID_VARIABLE_CLEANUP,
    784     StartOpCodeHandle, // LABEL_START
    785     EndOpCodeHandle    // LABEL_END
    786     );
    787 
    788   HiiFreeOpCodeHandle (StartOpCodeHandle);
    789   HiiFreeOpCodeHandle (EndOpCodeHandle);
    790 }
    791 
    792 /**
    793   This function applies changes in a driver's configuration.
    794   Input is a Configuration, which has the routing data for this
    795   driver followed by name / value configuration pairs. The driver
    796   must apply those pairs to its configurable storage. If the
    797   driver's configuration is stored in a linear block of data
    798   and the driver's name / value pairs are in <BlockConfig>
    799   format, it may use the ConfigToBlock helper function (above) to
    800   simplify the job. Currently not implemented.
    801 
    802   @param[in]  This                  Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    803   @param[in]  Configuration         A null-terminated Unicode string in
    804                                     <ConfigString> format.
    805   @param[out] Progress              A pointer to a string filled in with the
    806                                     offset of the most recent '&' before the
    807                                     first failing name / value pair (or the
    808                                     beginn ing of the string if the failure
    809                                     is in the first name / value pair) or
    810                                     the terminating NULL if all was
    811                                     successful.
    812 
    813   @retval EFI_SUCCESS               The results have been distributed or are
    814                                     awaiting distribution.
    815   @retval EFI_OUT_OF_RESOURCES      Not enough memory to store the
    816                                     parts of the results that must be
    817                                     stored awaiting possible future
    818                                     protocols.
    819   @retval EFI_INVALID_PARAMETERS    Passing in a NULL for the
    820                                     Results parameter would result
    821                                     in this type of error.
    822   @retval EFI_NOT_FOUND             Target for the specified routing data
    823                                     was not found.
    824 
    825 **/
    826 EFI_STATUS
    827 EFIAPI
    828 VariableCleanupHiiRouteConfig (
    829   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL      *This,
    830   IN  CONST EFI_STRING                          Configuration,
    831   OUT EFI_STRING                                *Progress
    832   )
    833 {
    834   EFI_STATUS                        Status;
    835   VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
    836   UINTN                             BufferSize;
    837 
    838   if (Progress == NULL) {
    839     return EFI_INVALID_PARAMETER;
    840   }
    841   *Progress = Configuration;
    842 
    843   if (Configuration == NULL) {
    844     return EFI_INVALID_PARAMETER;
    845   }
    846 
    847   //
    848   // Check routing data in <ConfigHdr>.
    849   // Note: there is no name for Name/Value storage, only GUID will be checked.
    850   //
    851   if (!HiiIsConfigHdrMatch (Configuration, &mVariableCleanupHiiGuid, mVarStoreName)) {
    852     return EFI_NOT_FOUND;
    853   }
    854 
    855   Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
    856   //
    857   // Get Buffer Storage data.
    858   //
    859   BufferSize = sizeof (VARIABLE_CLEANUP_DATA);
    860   //
    861   // Convert <ConfigResp> to buffer data by helper function ConfigToBlock().
    862   //
    863   Status = Private->ConfigRouting->ConfigToBlock (
    864                             Private->ConfigRouting,
    865                             Configuration,
    866                             (UINT8 *) &Private->VariableCleanupData,
    867                             &BufferSize,
    868                             Progress
    869                             );
    870   ASSERT_EFI_ERROR (Status);
    871 
    872   DeleteUserVariable (FALSE, &Private->VariableCleanupData);
    873   //
    874   // For "F10" hotkey to refresh the form.
    875   //
    876 //  UpdateUserVariableForm (Private);
    877 
    878   return EFI_SUCCESS;
    879 }
    880 
    881 /**
    882   This function is called to provide results data to the driver.
    883   This data consists of a unique key that is used to identify
    884   which data is either being passed back or being asked for.
    885 
    886   @param[in]  This                  Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
    887   @param[in]  Action                Specifies the type of action taken by the browser.
    888   @param[in]  QuestionId            A unique value which is sent to the original
    889                                     exporting driver so that it can identify the type
    890                                     of data to expect. The format of the data tends to
    891                                     vary based on the opcode that generated the callback.
    892   @param[in]  Type                  The type of value for the question.
    893   @param[in]  Value                 A pointer to the data being sent to the original
    894                                     exporting driver.
    895   @param[out] ActionRequest         On return, points to the action requested by the
    896                                     callback function.
    897 
    898   @retval EFI_SUCCESS               The callback successfully handled the action.
    899   @retval EFI_OUT_OF_RESOURCES      Not enough storage is available to hold the
    900                                     variable and its data.
    901   @retval EFI_DEVICE_ERROR          The variable could not be saved.
    902   @retval EFI_UNSUPPORTED           The specified Action is not supported by the
    903                                     callback.
    904 **/
    905 EFI_STATUS
    906 EFIAPI
    907 VariableCleanupHiiCallback (
    908   IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
    909   IN  EFI_BROWSER_ACTION                     Action,
    910   IN  EFI_QUESTION_ID                        QuestionId,
    911   IN  UINT8                                  Type,
    912   IN  EFI_IFR_TYPE_VALUE                     *Value,
    913   OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
    914   )
    915 {
    916   VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;
    917   VARIABLE_CLEANUP_DATA             *VariableCleanupData;
    918 
    919   Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);
    920 
    921   if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {
    922     //
    923     // All other action return unsupported.
    924     //
    925     return EFI_UNSUPPORTED;
    926   }
    927 
    928   //
    929   // Retrieve uncommitted data from Form Browser.
    930   //
    931   VariableCleanupData = &Private->VariableCleanupData;
    932   HiiGetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData);
    933   if (Action == EFI_BROWSER_ACTION_CHANGING) {
    934     if (Value == NULL) {
    935       return EFI_INVALID_PARAMETER;
    936     }
    937   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
    938     if ((Value == NULL) || (ActionRequest == NULL)) {
    939       return EFI_INVALID_PARAMETER;
    940     }
    941     if ((QuestionId >= USER_VARIABLE_QUESTION_ID) && (QuestionId < USER_VARIABLE_QUESTION_ID + MAX_USER_VARIABLE_COUNT)) {
    942       if (Value->b){
    943         //
    944         // Means one user variable checkbox is marked to delete but not press F10 or "Commit Changes and Exit" menu.
    945         //
    946         mMarkedUserVariableCount++;
    947         ASSERT (mMarkedUserVariableCount <= mUserVariableCount);
    948         if (mMarkedUserVariableCount == mUserVariableCount) {
    949           //
    950           // All user variables have been marked, then also mark the SelectAll checkbox.
    951           //
    952           VariableCleanupData->SelectAll = TRUE;
    953         }
    954       } else {
    955         //
    956         // Means one user variable checkbox is unmarked.
    957         //
    958         mMarkedUserVariableCount--;
    959         //
    960         // Also unmark the SelectAll checkbox.
    961         //
    962         VariableCleanupData->SelectAll = FALSE;
    963       }
    964     } else {
    965       switch (QuestionId) {
    966         case SELECT_ALL_QUESTION_ID:
    967          if (Value->b){
    968             //
    969             // Means the SelectAll checkbox is marked to delete all user variables but not press F10 or "Commit Changes and Exit" menu.
    970             //
    971             SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), TRUE);
    972             mMarkedUserVariableCount = mUserVariableCount;
    973           } else {
    974             //
    975             // Means the SelectAll checkbox is unmarked.
    976             //
    977             SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), FALSE);
    978             mMarkedUserVariableCount = 0;
    979           }
    980           break;
    981         case SAVE_AND_EXIT_QUESTION_ID:
    982           DeleteUserVariable (FALSE, VariableCleanupData);
    983           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
    984           break;
    985 
    986         case NO_SAVE_AND_EXIT_QUESTION_ID:
    987           //
    988           // Restore local maintain data.
    989           //
    990           *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
    991           break;
    992 
    993         default:
    994           break;
    995       }
    996     }
    997   }
    998 
    999   //
   1000   // Pass changed uncommitted data back to Form Browser.
   1001   //
   1002   HiiSetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData, NULL);
   1003   return EFI_SUCCESS;
   1004 }
   1005 
   1006 /**
   1007   Platform variable cleanup.
   1008 
   1009   @param[in] Flag                   Variable error flag.
   1010   @param[in] Type                   Variable cleanup type.
   1011                                     If it is VarCleanupManually, the interface must be called after console connected.
   1012 
   1013   @retval EFI_SUCCESS               No error or error processed.
   1014   @retval EFI_UNSUPPORTED           The specified Flag or Type is not supported.
   1015                                     For example, system error may be not supported to process and Platform should have mechanism to reset system to manufacture mode.
   1016                                     Another, if system and user variables are wanted to be distinguished to process, the interface must be called after EndOfDxe.
   1017   @retval EFI_OUT_OF_RESOURCES      Not enough resource to process the error.
   1018   @retval EFI_INVALID_PARAMETER     The specified Flag or Type is an invalid value.
   1019   @retval Others                    Other failure occurs.
   1020 
   1021 **/
   1022 EFI_STATUS
   1023 EFIAPI
   1024 PlatformVarCleanup (
   1025   IN VAR_ERROR_FLAG     Flag,
   1026   IN VAR_CLEANUP_TYPE   Type
   1027   )
   1028 {
   1029   EFI_STATUS                            Status;
   1030   EFI_FORM_BROWSER2_PROTOCOL            *FormBrowser2;
   1031   VARIABLE_CLEANUP_HII_PRIVATE_DATA     *Private;
   1032 
   1033   if (!mEndOfDxe) {
   1034     //
   1035     // This implementation must be called after EndOfDxe.
   1036     //
   1037     return EFI_UNSUPPORTED;
   1038   }
   1039 
   1040   if ((Type >= VarCleanupMax) || ((Flag & ((VAR_ERROR_FLAG) (VAR_ERROR_FLAG_SYSTEM_ERROR & VAR_ERROR_FLAG_USER_ERROR))) == 0)) {
   1041     return EFI_INVALID_PARAMETER;
   1042   }
   1043 
   1044   if (Flag == VAR_ERROR_FLAG_NO_ERROR) {
   1045     //
   1046     // Just return success if no error.
   1047     //
   1048     return EFI_SUCCESS;
   1049   }
   1050 
   1051   if ((Flag & (~((VAR_ERROR_FLAG) VAR_ERROR_FLAG_SYSTEM_ERROR))) == 0) {
   1052     //
   1053     // This sample does not support system variables cleanup.
   1054     //
   1055     DEBUG ((EFI_D_ERROR, "NOTICE - VAR_ERROR_FLAG_SYSTEM_ERROR\n"));
   1056     DEBUG ((EFI_D_ERROR, "Platform should have mechanism to reset system to manufacture mode\n"));
   1057     return EFI_UNSUPPORTED;
   1058   }
   1059 
   1060   //
   1061   // Continue to process VAR_ERROR_FLAG_USER_ERROR.
   1062   //
   1063 
   1064   //
   1065   // Create user variable nodes for the following processing.
   1066   //
   1067   CreateUserVariableNode ();
   1068 
   1069   switch (Type) {
   1070     case VarCleanupAll:
   1071       DeleteUserVariable (TRUE, NULL);
   1072       //
   1073       // Destroyed the created user variable nodes
   1074       //
   1075       DestroyUserVariableNode ();
   1076       return EFI_SUCCESS;
   1077       break;
   1078 
   1079     case VarCleanupManually:
   1080       //
   1081       // Locate FormBrowser2 protocol.
   1082       //
   1083       Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);
   1084       if (EFI_ERROR (Status)) {
   1085         return Status;
   1086       }
   1087 
   1088       Private = AllocateZeroPool (sizeof (VARIABLE_CLEANUP_HII_PRIVATE_DATA));
   1089       if (Private == NULL) {
   1090         return EFI_OUT_OF_RESOURCES;
   1091       }
   1092 
   1093       Private->Signature = VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE;
   1094       Private->ConfigAccess.ExtractConfig = VariableCleanupHiiExtractConfig;
   1095       Private->ConfigAccess.RouteConfig   = VariableCleanupHiiRouteConfig;
   1096       Private->ConfigAccess.Callback      = VariableCleanupHiiCallback;
   1097 
   1098       Status = gBS->LocateProtocol (
   1099                       &gEfiHiiConfigRoutingProtocolGuid,
   1100                       NULL,
   1101                       (VOID **) &Private->ConfigRouting
   1102                       );
   1103       if (EFI_ERROR (Status)) {
   1104         goto Done;
   1105       }
   1106 
   1107       //
   1108       // Install Device Path Protocol and Config Access protocol to driver handle.
   1109       //
   1110       Status = gBS->InstallMultipleProtocolInterfaces (
   1111                       &Private->DriverHandle,
   1112                       &gEfiDevicePathProtocolGuid,
   1113                       &mVarCleanupHiiVendorDevicePath,
   1114                       &gEfiHiiConfigAccessProtocolGuid,
   1115                       &Private->ConfigAccess,
   1116                       NULL
   1117                       );
   1118       if (EFI_ERROR (Status)) {
   1119         goto Done;
   1120       }
   1121 
   1122       //
   1123       // Publish our HII data.
   1124       //
   1125       Private->HiiHandle = HiiAddPackages (
   1126                              &mVariableCleanupHiiGuid,
   1127                              Private->DriverHandle,
   1128                              PlatformVarCleanupLibStrings,
   1129                              PlatVarCleanupBin,
   1130                              NULL
   1131                              );
   1132       if (Private->HiiHandle == NULL) {
   1133         Status = EFI_OUT_OF_RESOURCES;
   1134         goto Done;
   1135       }
   1136 
   1137       UpdateUserVariableForm (Private);
   1138 
   1139       Status = FormBrowser2->SendForm (
   1140                                FormBrowser2,
   1141                                &Private->HiiHandle,
   1142                                1,
   1143                                NULL,
   1144                                0,
   1145                                NULL,
   1146                                NULL
   1147                                );
   1148       break;
   1149 
   1150     default:
   1151       return EFI_UNSUPPORTED;
   1152       break;
   1153   }
   1154 
   1155 Done:
   1156   if (Private->DriverHandle != NULL) {
   1157     gBS->UninstallMultipleProtocolInterfaces (
   1158            Private->DriverHandle,
   1159            &gEfiDevicePathProtocolGuid,
   1160            &mVarCleanupHiiVendorDevicePath,
   1161            &gEfiHiiConfigAccessProtocolGuid,
   1162            &Private->ConfigAccess,
   1163            NULL
   1164            );
   1165   }
   1166   if (Private->HiiHandle != NULL) {
   1167     HiiRemovePackages (Private->HiiHandle);
   1168   }
   1169 
   1170   FreePool (Private);
   1171 
   1172   //
   1173   // Destroyed the created user variable nodes
   1174   //
   1175   DestroyUserVariableNode ();
   1176   return Status;
   1177 }
   1178 
   1179 /**
   1180   Get last boot variable error flag.
   1181 
   1182   @return   Last boot variable error flag.
   1183 
   1184 **/
   1185 VAR_ERROR_FLAG
   1186 EFIAPI
   1187 GetLastBootVarErrorFlag (
   1188   )
   1189 {
   1190   return mLastVarErrorFlag;
   1191 }
   1192 
   1193 /**
   1194   Notification function of END_OF_DXE.
   1195 
   1196   This is a notification function registered on END_OF_DXE event.
   1197 
   1198   @param[in] Event      Event whose notification function is being invoked.
   1199   @param[in] Context    Pointer to the notification function's context.
   1200 
   1201 **/
   1202 VOID
   1203 EFIAPI
   1204 PlatformVarCleanupEndOfDxeEvent (
   1205   IN EFI_EVENT  Event,
   1206   IN VOID       *Context
   1207   )
   1208 {
   1209   mEndOfDxe = TRUE;
   1210 }
   1211 
   1212 /**
   1213   The constructor function caches the pointer to VarCheck protocol and last boot variable error flag.
   1214 
   1215   The constructor function locates VarCheck protocol from protocol database.
   1216   It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
   1217 
   1218   @param  ImageHandle   The firmware allocated handle for the EFI image.
   1219   @param  SystemTable   A pointer to the EFI System Table.
   1220 
   1221   @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
   1222 
   1223 **/
   1224 EFI_STATUS
   1225 EFIAPI
   1226 PlatformVarCleanupLibConstructor (
   1227   IN EFI_HANDLE         ImageHandle,
   1228   IN EFI_SYSTEM_TABLE   *SystemTable
   1229   )
   1230 {
   1231   EFI_STATUS    Status;
   1232   EFI_EVENT     Event;
   1233 
   1234   mLastVarErrorFlag = InternalGetVarErrorFlag ();
   1235   DEBUG ((EFI_D_INFO, "mLastVarErrorFlag - 0x%02x\n", mLastVarErrorFlag));
   1236 
   1237   //
   1238   // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.
   1239   //
   1240   Status = gBS->CreateEventEx (
   1241                   EVT_NOTIFY_SIGNAL,
   1242                   TPL_CALLBACK,
   1243                   PlatformVarCleanupEndOfDxeEvent,
   1244                   NULL,
   1245                   &gEfiEndOfDxeEventGroupGuid,
   1246                   &Event
   1247                   );
   1248   ASSERT_EFI_ERROR (Status);
   1249 
   1250   return EFI_SUCCESS;
   1251 }
   1252 
   1253