+/** @file\r
+ Sample platform variable cleanup library implementation.\r
+\r
+Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "PlatVarCleanup.h"\r
+\r
+VAR_ERROR_FLAG mLastVarErrorFlag = VAR_ERROR_FLAG_NO_ERROR;\r
+EDKII_VAR_CHECK_PROTOCOL *mVarCheck = NULL;\r
+\r
+///\r
+/// The flag to indicate whether the platform has left the DXE phase of execution.\r
+///\r
+BOOLEAN mEndOfDxe = FALSE;\r
+\r
+LIST_ENTRY mUserVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mUserVariableList);\r
+UINT16 mUserVariableCount = 0;\r
+UINT16 mMarkedUserVariableCount = 0;\r
+\r
+EFI_GUID mVariableCleanupHiiGuid = VARIABLE_CLEANUP_HII_GUID;\r
+CHAR16 mVarStoreName[] = L"VariableCleanup";\r
+\r
+HII_VENDOR_DEVICE_PATH mVarCleanupHiiVendorDevicePath = {\r
+ {\r
+ {\r
+ HARDWARE_DEVICE_PATH,\r
+ HW_VENDOR_DP,\r
+ {\r
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),\r
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)\r
+ }\r
+ },\r
+ VARIABLE_CLEANUP_HII_GUID\r
+ },\r
+ {\r
+ END_DEVICE_PATH_TYPE,\r
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+ {\r
+ (UINT8) (sizeof (EFI_DEVICE_PATH_PROTOCOL)),\r
+ (UINT8) ((sizeof (EFI_DEVICE_PATH_PROTOCOL)) >> 8)\r
+ }\r
+ }\r
+};\r
+\r
+/**\r
+ Internal get variable error flag.\r
+\r
+ @return Variable error flag.\r
+\r
+**/\r
+VAR_ERROR_FLAG\r
+InternalGetVarErrorFlag (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINTN Size;\r
+ VAR_ERROR_FLAG ErrorFlag;\r
+\r
+ Size = sizeof (ErrorFlag);\r
+ Status = gRT->GetVariable (\r
+ VAR_ERROR_FLAG_NAME,\r
+ &gEdkiiVarErrorFlagGuid,\r
+ NULL,\r
+ &Size,\r
+ &ErrorFlag\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((EFI_D_INFO, "%s - not found\n", VAR_ERROR_FLAG_NAME));\r
+ return VAR_ERROR_FLAG_NO_ERROR;\r
+ }\r
+ return ErrorFlag;\r
+}\r
+\r
+/**\r
+ Is user variable?\r
+\r
+ @param[in] Name Pointer to variable name.\r
+ @param[in] Guid Pointer to vendor guid.\r
+\r
+ @retval TRUE User variable.\r
+ @retval FALSE System variable.\r
+\r
+**/\r
+BOOLEAN\r
+IsUserVariable (\r
+ IN CHAR16 *Name,\r
+ IN EFI_GUID *Guid\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VAR_CHECK_VARIABLE_PROPERTY Property;\r
+\r
+ ZeroMem (&Property, sizeof (Property));\r
+ Status = mVarCheck->VariablePropertyGet (\r
+ Name,\r
+ Guid,\r
+ &Property\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // No property, it is user variable.\r
+ //\r
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable: %g:%s\n", Guid, Name));\r
+ return TRUE;\r
+ }\r
+\r
+// DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Variable Property: %g:%s\n", Guid, Name));\r
+// DEBUG ((EFI_D_INFO, " Revision - 0x%04x\n", Property.Revision));\r
+// DEBUG ((EFI_D_INFO, " Property - 0x%04x\n", Property.Property));\r
+// DEBUG ((EFI_D_INFO, " Attribute - 0x%08x\n", Property.Attributes));\r
+// DEBUG ((EFI_D_INFO, " MinSize - 0x%x\n", Property.MinSize));\r
+// DEBUG ((EFI_D_INFO, " MaxSize - 0x%x\n", Property.MaxSize));\r
+\r
+ return FALSE;\r
+}\r
+\r
+/**\r
+ Find user variable node by variable GUID.\r
+\r
+ @param[in] Guid Pointer to vendor guid.\r
+\r
+ @return Pointer to user variable node.\r
+\r
+**/\r
+USER_VARIABLE_NODE *\r
+FindUserVariableNodeByGuid (\r
+ IN EFI_GUID *Guid\r
+ )\r
+{\r
+ USER_VARIABLE_NODE *UserVariableNode;\r
+ LIST_ENTRY *Link;\r
+\r
+ for (Link = mUserVariableList.ForwardLink\r
+ ;Link != &mUserVariableList\r
+ ;Link = Link->ForwardLink) {\r
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);\r
+\r
+ if (CompareGuid (Guid, &UserVariableNode->Guid)) {\r
+ //\r
+ // Found it.\r
+ //\r
+ return UserVariableNode;\r
+ }\r
+ }\r
+\r
+ //\r
+ // Create new one if not found.\r
+ //\r
+ UserVariableNode = AllocateZeroPool (sizeof (*UserVariableNode));\r
+ ASSERT (UserVariableNode != NULL);\r
+ UserVariableNode->Signature = USER_VARIABLE_NODE_SIGNATURE;\r
+ CopyGuid (&UserVariableNode->Guid, Guid);\r
+ //\r
+ // (36 chars of "########-####-####-####-############" + 1 space + 1 terminator) * sizeof (CHAR16).\r
+ //\r
+ UserVariableNode->PromptString = AllocatePool ((36 + 2) * sizeof (CHAR16));\r
+ ASSERT (UserVariableNode->PromptString != NULL);\r
+ UnicodeSPrint (UserVariableNode->PromptString, (36 + 2) * sizeof (CHAR16), L" %g", &UserVariableNode->Guid);\r
+ InitializeListHead (&UserVariableNode->NameLink);\r
+ InsertTailList (&mUserVariableList, &UserVariableNode->Link);\r
+ return UserVariableNode;\r
+}\r
+\r
+/**\r
+ Create user variable node.\r
+\r
+**/\r
+VOID\r
+CreateUserVariableNode (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_STATUS GetVariableStatus;\r
+ CHAR16 *VarName;\r
+ UINTN MaxVarNameSize;\r
+ UINTN VarNameSize;\r
+ UINTN MaxDataSize;\r
+ UINTN DataSize;\r
+ VOID *Data;\r
+ UINT32 Attributes;\r
+ EFI_GUID Guid;\r
+ USER_VARIABLE_NODE *UserVariableNode;\r
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;\r
+ UINT16 Index;\r
+ UINTN StringSize;\r
+\r
+ //\r
+ // Initialize 128 * sizeof (CHAR16) variable name size.\r
+ //\r
+ MaxVarNameSize = 128 * sizeof (CHAR16);\r
+ VarName = AllocateZeroPool (MaxVarNameSize);\r
+ ASSERT (VarName != NULL);\r
+\r
+ //\r
+ // Initialize 0x1000 variable data size.\r
+ //\r
+ MaxDataSize = 0x1000;\r
+ Data = AllocateZeroPool (MaxDataSize);\r
+ ASSERT (Data != NULL);\r
+\r
+ Index = 0;\r
+ do {\r
+ VarNameSize = MaxVarNameSize;\r
+ Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ VarName = ReallocatePool (MaxVarNameSize, VarNameSize, VarName);\r
+ ASSERT (VarName != NULL);\r
+ MaxVarNameSize = VarNameSize;\r
+ Status = gRT->GetNextVariableName (&VarNameSize, VarName, &Guid);\r
+ }\r
+\r
+ if (!EFI_ERROR (Status)) {\r
+ if (IsUserVariable (VarName, &Guid)) {\r
+ DataSize = MaxDataSize;\r
+ GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);\r
+ if (GetVariableStatus == EFI_BUFFER_TOO_SMALL) {\r
+ Data = ReallocatePool (MaxDataSize, DataSize, Data);\r
+ ASSERT (Data != NULL);\r
+ MaxDataSize = DataSize;\r
+ GetVariableStatus = gRT->GetVariable (VarName, &Guid, &Attributes, &DataSize, Data);\r
+ }\r
+ ASSERT_EFI_ERROR (GetVariableStatus);\r
+\r
+ if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
+ UserVariableNode = FindUserVariableNodeByGuid (&Guid);\r
+ ASSERT (UserVariableNode != NULL);\r
+\r
+ //\r
+ // Different variables that have same variable GUID share same user variable node.\r
+ //\r
+ UserVariableNameNode = AllocateZeroPool (sizeof (*UserVariableNameNode));\r
+ ASSERT (UserVariableNameNode != NULL);\r
+ UserVariableNameNode->Signature = USER_VARIABLE_NAME_NODE_SIGNATURE;\r
+ UserVariableNameNode->Name = AllocateCopyPool (VarNameSize, VarName);\r
+ UserVariableNameNode->Attributes = Attributes;\r
+ UserVariableNameNode->DataSize = DataSize;\r
+ UserVariableNameNode->Index = Index;\r
+ UserVariableNameNode->QuestionId = (EFI_QUESTION_ID) (USER_VARIABLE_QUESTION_ID + Index);\r
+ //\r
+ // 2 space * sizeof (CHAR16) + StrSize.\r
+ //\r
+ StringSize = 2 * sizeof (CHAR16) + StrSize (UserVariableNameNode->Name);\r
+ UserVariableNameNode->PromptString = AllocatePool (StringSize);\r
+ ASSERT (UserVariableNameNode->PromptString != NULL);\r
+ UnicodeSPrint (UserVariableNameNode->PromptString, StringSize, L" %s", UserVariableNameNode->Name);\r
+ //\r
+ // (33 chars of "Attribtues = 0x and DataSize = 0x" + 1 terminator + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16).\r
+ //\r
+ StringSize = (33 + 1 + (sizeof (UINT32) + sizeof (UINTN)) * 2) * sizeof (CHAR16);\r
+ UserVariableNameNode->HelpString = AllocatePool (StringSize);\r
+ ASSERT (UserVariableNameNode->HelpString != NULL);\r
+ UnicodeSPrint (UserVariableNameNode->HelpString, StringSize, L"Attribtues = 0x%08x and DataSize = 0x%x", UserVariableNameNode->Attributes, UserVariableNameNode->DataSize);\r
+ UserVariableNameNode->Deleted = FALSE;\r
+ InsertTailList (&UserVariableNode->NameLink, &UserVariableNameNode->Link);\r
+ Index++;\r
+ }\r
+ }\r
+ }\r
+ } while (Status != EFI_NOT_FOUND);\r
+\r
+ mUserVariableCount = Index;\r
+ ASSERT (mUserVariableCount <= MAX_USER_VARIABLE_COUNT);\r
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - User variable count: 0x%04x\n", mUserVariableCount));\r
+\r
+ FreePool (VarName);\r
+ FreePool (Data);\r
+}\r
+\r
+/**\r
+ Destroy user variable nodes.\r
+\r
+**/\r
+VOID\r
+DestroyUserVariableNode (\r
+ VOID\r
+ )\r
+{\r
+ USER_VARIABLE_NODE *UserVariableNode;\r
+ LIST_ENTRY *Link;\r
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;\r
+ LIST_ENTRY *NameLink;\r
+\r
+ while (mUserVariableList.ForwardLink != &mUserVariableList) {\r
+ Link = mUserVariableList.ForwardLink;\r
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);\r
+\r
+ RemoveEntryList (&UserVariableNode->Link);\r
+\r
+ while (UserVariableNode->NameLink.ForwardLink != &UserVariableNode->NameLink) {\r
+ NameLink = UserVariableNode->NameLink.ForwardLink;\r
+ UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);\r
+\r
+ RemoveEntryList (&UserVariableNameNode->Link);\r
+\r
+ FreePool (UserVariableNameNode->Name);\r
+ FreePool (UserVariableNameNode->PromptString);\r
+ FreePool (UserVariableNameNode->HelpString);\r
+ FreePool (UserVariableNameNode);\r
+ }\r
+\r
+ FreePool (UserVariableNode->PromptString);\r
+ FreePool (UserVariableNode);\r
+ }\r
+}\r
+\r
+/**\r
+ Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2\r
+ descriptor with the input data. NO authentication is required in this function.\r
+\r
+ @param[in, out] DataSize On input, the size of Data buffer in bytes.\r
+ On output, the size of data returned in Data\r
+ buffer in bytes.\r
+ @param[in, out] Data On input, Pointer to data buffer to be wrapped or\r
+ pointer to NULL to wrap an empty payload.\r
+ On output, Pointer to the new payload date buffer allocated from pool,\r
+ it's caller's responsibility to free the memory after using it.\r
+\r
+ @retval EFI_SUCCESS Create time based payload successfully.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.\r
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
+ @retval Others Unexpected error happens.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateTimeBasedPayload (\r
+ IN OUT UINTN *DataSize,\r
+ IN OUT UINT8 **Data\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *NewData;\r
+ UINT8 *Payload;\r
+ UINTN PayloadSize;\r
+ EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData;\r
+ UINTN DescriptorSize;\r
+ EFI_TIME Time;\r
+\r
+ if (Data == NULL || DataSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // At user physical presence, the variable does not need to be signed but the\r
+ // parameters to the SetVariable() call still need to be prepared as authenticated\r
+ // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate\r
+ // data in it.\r
+ //\r
+ Payload = *Data;\r
+ PayloadSize = *DataSize;\r
+\r
+ DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
+ NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);\r
+ if (NewData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if ((Payload != NULL) && (PayloadSize != 0)) {\r
+ CopyMem (NewData + DescriptorSize, Payload, PayloadSize);\r
+ }\r
+\r
+ DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);\r
+\r
+ ZeroMem (&Time, sizeof (EFI_TIME));\r
+ Status = gRT->GetTime (&Time, NULL);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (NewData);\r
+ return Status;\r
+ }\r
+ Time.Pad1 = 0;\r
+ Time.Nanosecond = 0;\r
+ Time.TimeZone = 0;\r
+ Time.Daylight = 0;\r
+ Time.Pad2 = 0;\r
+ CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));\r
+\r
+ DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
+ DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;\r
+ DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;\r
+ CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);\r
+\r
+ if (Payload != NULL) {\r
+ FreePool (Payload);\r
+ }\r
+\r
+ *DataSize = DescriptorSize + PayloadSize;\r
+ *Data = NewData;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Create a counter based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION\r
+ descriptor with the input data. NO authentication is required in this function.\r
+\r
+ @param[in, out] DataSize On input, the size of Data buffer in bytes.\r
+ On output, the size of data returned in Data\r
+ buffer in bytes.\r
+ @param[in, out] Data On input, Pointer to data buffer to be wrapped or\r
+ pointer to NULL to wrap an empty payload.\r
+ On output, Pointer to the new payload date buffer allocated from pool,\r
+ it's caller's responsibility to free the memory after using it.\r
+\r
+ @retval EFI_SUCCESS Create counter based payload successfully.\r
+ @retval EFI_OUT_OF_RESOURCES There are not enough memory resourses to create time based payload.\r
+ @retval EFI_INVALID_PARAMETER The parameter is invalid.\r
+ @retval Others Unexpected error happens.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateCounterBasedPayload (\r
+ IN OUT UINTN *DataSize,\r
+ IN OUT UINT8 **Data\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *NewData;\r
+ UINT8 *Payload;\r
+ UINTN PayloadSize;\r
+ EFI_VARIABLE_AUTHENTICATION *DescriptorData;\r
+ UINTN DescriptorSize;\r
+ UINT64 MonotonicCount;\r
+\r
+ if (Data == NULL || DataSize == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // At user physical presence, the variable does not need to be signed but the\r
+ // parameters to the SetVariable() call still need to be prepared as authenticated\r
+ // variable. So we create EFI_VARIABLE_AUTHENTICATED descriptor without certificate\r
+ // data in it.\r
+ //\r
+ Payload = *Data;\r
+ PayloadSize = *DataSize;\r
+\r
+ DescriptorSize = (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION, AuthInfo)) + \\r
+ (OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) + \\r
+ sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);\r
+ NewData = (UINT8 *) AllocateZeroPool (DescriptorSize + PayloadSize);\r
+ if (NewData == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if ((Payload != NULL) && (PayloadSize != 0)) {\r
+ CopyMem (NewData + DescriptorSize, Payload, PayloadSize);\r
+ }\r
+\r
+ DescriptorData = (EFI_VARIABLE_AUTHENTICATION *) (NewData);\r
+\r
+ Status = gBS->GetNextMonotonicCount (&MonotonicCount);\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (NewData);\r
+ return Status;\r
+ }\r
+ DescriptorData->MonotonicCount = MonotonicCount;\r
+\r
+ DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData) + sizeof (EFI_CERT_BLOCK_RSA_2048_SHA256);\r
+ DescriptorData->AuthInfo.Hdr.wRevision = 0x0200;\r
+ DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;\r
+ CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertTypeRsa2048Sha256Guid);\r
+\r
+ if (Payload != NULL) {\r
+ FreePool (Payload);\r
+ }\r
+\r
+ *DataSize = DescriptorSize + PayloadSize;\r
+ *Data = NewData;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Delete user variable.\r
+\r
+ @param[in] DeleteAll Delete all user variables.\r
+ @param[in] VariableCleanupData Pointer to variable cleanup data.\r
+\r
+**/\r
+VOID\r
+DeleteUserVariable (\r
+ IN BOOLEAN DeleteAll,\r
+ IN VARIABLE_CLEANUP_DATA *VariableCleanupData OPTIONAL\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ USER_VARIABLE_NODE *UserVariableNode;\r
+ LIST_ENTRY *Link;\r
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;\r
+ LIST_ENTRY *NameLink;\r
+ UINTN DataSize;\r
+ UINT8 *Data;\r
+\r
+ for (Link = mUserVariableList.ForwardLink\r
+ ;Link != &mUserVariableList\r
+ ;Link = Link->ForwardLink) {\r
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);\r
+\r
+ for (NameLink = UserVariableNode->NameLink.ForwardLink\r
+ ;NameLink != &UserVariableNode->NameLink\r
+ ;NameLink = NameLink->ForwardLink) {\r
+ UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);\r
+\r
+ if (!UserVariableNameNode->Deleted && (DeleteAll || ((VariableCleanupData != NULL) && (VariableCleanupData->UserVariable[UserVariableNameNode->Index] == TRUE)))) {\r
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));\r
+ if ((UserVariableNameNode->Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ DataSize = 0;\r
+ Data = NULL;\r
+ Status = CreateTimeBasedPayload (&DataSize, &Data);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);\r
+ FreePool (Data);\r
+ }\r
+ } else if ((UserVariableNameNode->Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+ DataSize = 0;\r
+ Data = NULL;\r
+ Status = CreateCounterBasedPayload (&DataSize, &Data);\r
+ if (!EFI_ERROR (Status)) {\r
+ Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, UserVariableNameNode->Attributes, DataSize, Data);\r
+ FreePool (Data);\r
+ }\r
+ } else {\r
+ Status = gRT->SetVariable (UserVariableNameNode->Name, &UserVariableNode->Guid, 0, 0, NULL);\r
+ }\r
+ if (!EFI_ERROR (Status)) {\r
+ UserVariableNameNode->Deleted = TRUE;\r
+ } else {\r
+ DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Delete variable fail: %g:%s\n", &UserVariableNode->Guid, UserVariableNameNode->Name));\r
+ }\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/**\r
+ This function allows a caller to extract the current configuration for one\r
+ or more named elements from the target driver.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param[in] Request A null-terminated Unicode string in <ConfigRequest> format.\r
+ @param[out] Progress On return, points to a character in the Request string.\r
+ Points to the string's null terminator if request was successful.\r
+ Points to the most recent '&' before the first failing name/value\r
+ pair (or the beginning of the string if the failure is in the\r
+ first name/value pair) if the request was not successful.\r
+ @param[out] Results A null-terminated Unicode string in <ConfigAltResp> format which\r
+ has all values filled in for the names in the Request string.\r
+ String to be allocated by the called function.\r
+\r
+ @retval EFI_SUCCESS The Results is filled with the requested values.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.\r
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.\r
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableCleanupHiiExtractConfig (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN CONST EFI_STRING Request,\r
+ OUT EFI_STRING *Progress,\r
+ OUT EFI_STRING *Results\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;\r
+ UINTN BufferSize;\r
+ EFI_STRING ConfigRequestHdr;\r
+ EFI_STRING ConfigRequest;\r
+ BOOLEAN AllocatedRequest;\r
+ UINTN Size;\r
+\r
+ if (Progress == NULL || Results == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ *Progress = Request;\r
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &mVariableCleanupHiiGuid, mVarStoreName)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ ConfigRequestHdr = NULL;\r
+ ConfigRequest = NULL;\r
+ AllocatedRequest = FALSE;\r
+ Size = 0;\r
+\r
+ Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);\r
+ //\r
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig().\r
+ //\r
+ BufferSize = sizeof (VARIABLE_CLEANUP_DATA);\r
+ ConfigRequest = Request;\r
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {\r
+ //\r
+ // Request has no request element, construct full request string.\r
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template\r
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator.\r
+ //\r
+ ConfigRequestHdr = HiiConstructConfigHdr (&mVariableCleanupHiiGuid, mVarStoreName, Private->HiiHandle);\r
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);\r
+ ConfigRequest = AllocateZeroPool (Size);\r
+ ASSERT (ConfigRequest != NULL);\r
+ AllocatedRequest = TRUE;\r
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);\r
+ FreePool (ConfigRequestHdr);\r
+ }\r
+\r
+ Status = Private->ConfigRouting->BlockToConfig (\r
+ Private->ConfigRouting,\r
+ ConfigRequest,\r
+ (UINT8 *) &Private->VariableCleanupData,\r
+ BufferSize,\r
+ Results,\r
+ Progress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Free the allocated config request string.\r
+ //\r
+ if (AllocatedRequest) {\r
+ FreePool (ConfigRequest);\r
+ ConfigRequest = NULL;\r
+ }\r
+ //\r
+ // Set Progress string to the original request string or the string's null terminator.\r
+ //\r
+ if (Request == NULL) {\r
+ *Progress = NULL;\r
+ } else if (StrStr (Request, L"OFFSET") == NULL) {\r
+ *Progress = Request + StrLen (Request);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Update user variable form.\r
+\r
+ @param[in] Private Points to the VARIABLE_CLEANUP_HII_PRIVATE_DATA.\r
+\r
+**/\r
+VOID\r
+UpdateUserVariableForm (\r
+ IN VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private\r
+ )\r
+{\r
+ EFI_STRING_ID PromptStringToken;\r
+ EFI_STRING_ID HelpStringToken;\r
+ VOID *StartOpCodeHandle;\r
+ VOID *EndOpCodeHandle;\r
+ EFI_IFR_GUID_LABEL *StartLabel;\r
+ EFI_IFR_GUID_LABEL *EndLabel;\r
+ USER_VARIABLE_NODE *UserVariableNode;\r
+ LIST_ENTRY *Link;\r
+ USER_VARIABLE_NAME_NODE *UserVariableNameNode;\r
+ LIST_ENTRY *NameLink;\r
+ BOOLEAN Created;\r
+\r
+ //\r
+ // Init OpCode Handle.\r
+ //\r
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+ ASSERT (StartOpCodeHandle != NULL);\r
+\r
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();\r
+ ASSERT (EndOpCodeHandle != NULL);\r
+\r
+ //\r
+ // Create Hii Extend Label OpCode as the start opcode.\r
+ //\r
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+ StartLabel->Number = LABEL_START;\r
+\r
+ //\r
+ // Create Hii Extend Label OpCode as the end opcode.\r
+ //\r
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));\r
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;\r
+ EndLabel->Number = LABEL_END;\r
+\r
+ HiiUpdateForm (\r
+ Private->HiiHandle,\r
+ &mVariableCleanupHiiGuid,\r
+ FORM_ID_VARIABLE_CLEANUP,\r
+ StartOpCodeHandle, // LABEL_START\r
+ EndOpCodeHandle // LABEL_END\r
+ );\r
+\r
+ for (Link = mUserVariableList.ForwardLink\r
+ ;Link != &mUserVariableList\r
+ ;Link = Link->ForwardLink) {\r
+ UserVariableNode = USER_VARIABLE_FROM_LINK (Link);\r
+\r
+ //\r
+ // Create checkbox opcode for variables in the same variable GUID space.\r
+ //\r
+ Created = FALSE;\r
+ for (NameLink = UserVariableNode->NameLink.ForwardLink\r
+ ;NameLink != &UserVariableNode->NameLink\r
+ ;NameLink = NameLink->ForwardLink) {\r
+ UserVariableNameNode = USER_VARIABLE_NAME_FROM_LINK (NameLink);\r
+\r
+ if (!UserVariableNameNode->Deleted) {\r
+ if (!Created) {\r
+ //\r
+ // Create subtitle opcode for variable GUID.\r
+ //\r
+ PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNode->PromptString, NULL);\r
+ HiiCreateSubTitleOpCode (StartOpCodeHandle, PromptStringToken, 0, 0, 0);\r
+ Created = TRUE;\r
+ }\r
+\r
+ //\r
+ // Only create opcode for the non-deleted variables.\r
+ //\r
+ PromptStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->PromptString, NULL);\r
+ HelpStringToken = HiiSetString (Private->HiiHandle, 0, UserVariableNameNode->HelpString, NULL);\r
+ HiiCreateCheckBoxOpCode (\r
+ StartOpCodeHandle,\r
+ UserVariableNameNode->QuestionId,\r
+ VARIABLE_CLEANUP_VARSTORE_ID,\r
+ (UINT16) (USER_VARIABLE_VAR_OFFSET + UserVariableNameNode->Index),\r
+ PromptStringToken,\r
+ HelpStringToken,\r
+ EFI_IFR_FLAG_CALLBACK,\r
+ Private->VariableCleanupData.UserVariable[UserVariableNameNode->Index],\r
+ NULL\r
+ );\r
+ }\r
+ }\r
+ }\r
+\r
+ HiiCreateSubTitleOpCode (\r
+ StartOpCodeHandle,\r
+ STRING_TOKEN (STR_NULL_STRING),\r
+ 0,\r
+ 0,\r
+ 0\r
+ );\r
+\r
+ //\r
+ // Create the "Apply changes" and "Discard changes" tags.\r
+ //\r
+ HiiCreateActionOpCode (\r
+ StartOpCodeHandle,\r
+ SAVE_AND_EXIT_QUESTION_ID,\r
+ STRING_TOKEN (STR_SAVE_AND_EXIT),\r
+ STRING_TOKEN (STR_NULL_STRING),\r
+ EFI_IFR_FLAG_CALLBACK,\r
+ 0\r
+ );\r
+ HiiCreateActionOpCode (\r
+ StartOpCodeHandle,\r
+ NO_SAVE_AND_EXIT_QUESTION_ID,\r
+ STRING_TOKEN (STR_NO_SAVE_AND_EXIT),\r
+ STRING_TOKEN (STR_NULL_STRING),\r
+ EFI_IFR_FLAG_CALLBACK,\r
+ 0\r
+ );\r
+\r
+ HiiUpdateForm (\r
+ Private->HiiHandle,\r
+ &mVariableCleanupHiiGuid,\r
+ FORM_ID_VARIABLE_CLEANUP,\r
+ StartOpCodeHandle, // LABEL_START\r
+ EndOpCodeHandle // LABEL_END\r
+ );\r
+\r
+ HiiFreeOpCodeHandle (StartOpCodeHandle);\r
+ HiiFreeOpCodeHandle (EndOpCodeHandle);\r
+}\r
+\r
+/**\r
+ This function applies changes in a driver's configuration.\r
+ Input is a Configuration, which has the routing data for this\r
+ driver followed by name / value configuration pairs. The driver\r
+ must apply those pairs to its configurable storage. If the\r
+ driver's configuration is stored in a linear block of data\r
+ and the driver's name / value pairs are in <BlockConfig>\r
+ format, it may use the ConfigToBlock helper function (above) to\r
+ simplify the job. Currently not implemented.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param[in] Configuration A null-terminated Unicode string in\r
+ <ConfigString> format.\r
+ @param[out] Progress A pointer to a string filled in with the\r
+ offset of the most recent '&' before the\r
+ first failing name / value pair (or the\r
+ beginn ing of the string if the failure\r
+ is in the first name / value pair) or\r
+ the terminating NULL if all was\r
+ successful.\r
+\r
+ @retval EFI_SUCCESS The results have been distributed or are\r
+ awaiting distribution.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the\r
+ parts of the results that must be\r
+ stored awaiting possible future\r
+ protocols.\r
+ @retval EFI_INVALID_PARAMETERS Passing in a NULL for the\r
+ Results parameter would result\r
+ in this type of error.\r
+ @retval EFI_NOT_FOUND Target for the specified routing data\r
+ was not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableCleanupHiiRouteConfig (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN CONST EFI_STRING Configuration,\r
+ OUT EFI_STRING *Progress\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;\r
+ UINTN BufferSize;\r
+\r
+ if (Progress == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ *Progress = Configuration;\r
+\r
+ if (Configuration == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Check routing data in <ConfigHdr>.\r
+ // Note: there is no name for Name/Value storage, only GUID will be checked.\r
+ //\r
+ if (!HiiIsConfigHdrMatch (Configuration, &mVariableCleanupHiiGuid, mVarStoreName)) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);\r
+ //\r
+ // Get Buffer Storage data.\r
+ //\r
+ BufferSize = sizeof (VARIABLE_CLEANUP_DATA);\r
+ //\r
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock().\r
+ //\r
+ Status = Private->ConfigRouting->ConfigToBlock (\r
+ Private->ConfigRouting,\r
+ Configuration,\r
+ (UINT8 *) &Private->VariableCleanupData,\r
+ &BufferSize,\r
+ Progress\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ DeleteUserVariable (FALSE, &Private->VariableCleanupData);\r
+ //\r
+ // For "F10" hotkey to refresh the form.\r
+ //\r
+// UpdateUserVariableForm (Private);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ This function is called to provide results data to the driver.\r
+ This data consists of a unique key that is used to identify\r
+ which data is either being passed back or being asked for.\r
+\r
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.\r
+ @param[in] Action Specifies the type of action taken by the browser.\r
+ @param[in] QuestionId A unique value which is sent to the original\r
+ exporting driver so that it can identify the type\r
+ of data to expect. The format of the data tends to\r
+ vary based on the opcode that generated the callback.\r
+ @param[in] Type The type of value for the question.\r
+ @param[in] Value A pointer to the data being sent to the original\r
+ exporting driver.\r
+ @param[out] ActionRequest On return, points to the action requested by the\r
+ callback function.\r
+\r
+ @retval EFI_SUCCESS The callback successfully handled the action.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the\r
+ variable and its data.\r
+ @retval EFI_DEVICE_ERROR The variable could not be saved.\r
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the\r
+ callback.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+VariableCleanupHiiCallback (\r
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,\r
+ IN EFI_BROWSER_ACTION Action,\r
+ IN EFI_QUESTION_ID QuestionId,\r
+ IN UINT8 Type,\r
+ IN EFI_IFR_TYPE_VALUE *Value,\r
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest\r
+ )\r
+{\r
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;\r
+ VARIABLE_CLEANUP_DATA *VariableCleanupData;\r
+\r
+ Private = VARIABLE_CLEANUP_HII_PRIVATE_FROM_THIS (This);\r
+\r
+ if ((Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_CHANGED)) {\r
+ //\r
+ // All other action return unsupported.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Retrive uncommitted data from Form Browser.\r
+ //\r
+ VariableCleanupData = &Private->VariableCleanupData;\r
+ HiiGetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData);\r
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {\r
+ if (Value == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
+ if ((Value == NULL) || (ActionRequest == NULL)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ if ((QuestionId >= USER_VARIABLE_QUESTION_ID) && (QuestionId < USER_VARIABLE_QUESTION_ID + MAX_USER_VARIABLE_COUNT)) {\r
+ if (Value->b){\r
+ //\r
+ // Means one user variable checkbox is marked to delete but not press F10 or "Commit Changes and Exit" menu.\r
+ //\r
+ mMarkedUserVariableCount++;\r
+ ASSERT (mMarkedUserVariableCount <= mUserVariableCount);\r
+ if (mMarkedUserVariableCount == mUserVariableCount) {\r
+ //\r
+ // All user variables have been marked, then also mark the SelectAll checkbox.\r
+ //\r
+ VariableCleanupData->SelectAll = TRUE;\r
+ }\r
+ } else {\r
+ //\r
+ // Means one user variable checkbox is unmarked.\r
+ //\r
+ mMarkedUserVariableCount--;\r
+ //\r
+ // Also unmark the SelectAll checkbox.\r
+ //\r
+ VariableCleanupData->SelectAll = FALSE;\r
+ }\r
+ } else {\r
+ switch (QuestionId) {\r
+ case SELECT_ALL_QUESTION_ID:\r
+ if (Value->b){\r
+ //\r
+ // Means the SelectAll checkbox is marked to delete all user variables but not press F10 or "Commit Changes and Exit" menu.\r
+ //\r
+ SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), TRUE);\r
+ mMarkedUserVariableCount = mUserVariableCount;\r
+ } else {\r
+ //\r
+ // Means the SelectAll checkbox is unmarked.\r
+ //\r
+ SetMem (VariableCleanupData->UserVariable, sizeof (VariableCleanupData->UserVariable), FALSE);\r
+ mMarkedUserVariableCount = 0;\r
+ }\r
+ break;\r
+ case SAVE_AND_EXIT_QUESTION_ID:\r
+ DeleteUserVariable (FALSE, VariableCleanupData);\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;\r
+ break;\r
+\r
+ case NO_SAVE_AND_EXIT_QUESTION_ID:\r
+ //\r
+ // Restore local maintain data.\r
+ //\r
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ //\r
+ // Pass changed uncommitted data back to Form Browser.\r
+ //\r
+ HiiSetBrowserData (&mVariableCleanupHiiGuid, mVarStoreName, sizeof (VARIABLE_CLEANUP_DATA), (UINT8 *) VariableCleanupData, NULL);\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Platform variable cleanup.\r
+\r
+ @param[in] Flag Variable error flag.\r
+ @param[in] Type Variable cleanup type.\r
+ If it is VarCleanupManually, the interface must be called after console connected.\r
+\r
+ @retval EFI_SUCCESS No error or error processed.\r
+ @retval EFI_UNSUPPORTED The specified Flag or Type is not supported.\r
+ For example, system error may be not supported to process and Platform should have mechanism to reset system to manufacture mode.\r
+ Another, if system and user variables are wanted to be distinguished to process, the interface must be called after EndOfDxe.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to process the error.\r
+ @retval EFI_INVALID_PARAMETER The specified Flag or Type is an invalid value.\r
+ @retval Others Other failure occurs.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PlatformVarCleanup (\r
+ IN VAR_ERROR_FLAG Flag,\r
+ IN VAR_CLEANUP_TYPE Type\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_FORM_BROWSER2_PROTOCOL *FormBrowser2;\r
+ VARIABLE_CLEANUP_HII_PRIVATE_DATA *Private;\r
+\r
+ if (!mEndOfDxe) {\r
+ //\r
+ // This implementation must be called after EndOfDxe.\r
+ //\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ if ((Type >= VarCleanupMax) || ((Flag & ((VAR_ERROR_FLAG) (VAR_ERROR_FLAG_SYSTEM_ERROR & VAR_ERROR_FLAG_USER_ERROR))) == 0)) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (Flag == VAR_ERROR_FLAG_NO_ERROR) {\r
+ //\r
+ // Just return success if no error.\r
+ //\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ if ((Flag & (~((VAR_ERROR_FLAG) VAR_ERROR_FLAG_SYSTEM_ERROR))) == 0) {\r
+ //\r
+ // This sample does not support system variables cleanup.\r
+ //\r
+ DEBUG ((EFI_D_ERROR, "NOTICE - VAR_ERROR_FLAG_SYSTEM_ERROR\n"));\r
+ DEBUG ((EFI_D_ERROR, "Platform should have mechanism to reset system to manufacture mode\n"));\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Continue to process VAR_ERROR_FLAG_USER_ERROR.\r
+ //\r
+\r
+ //\r
+ // Create user variable nodes for the following processing.\r
+ //\r
+ CreateUserVariableNode ();\r
+\r
+ switch (Type) {\r
+ case VarCleanupAll:\r
+ DeleteUserVariable (TRUE, NULL);\r
+ //\r
+ // Destroyed the created user variable nodes\r
+ //\r
+ DestroyUserVariableNode ();\r
+ return EFI_SUCCESS;\r
+ break;\r
+\r
+ case VarCleanupManually:\r
+ //\r
+ // Locate FormBrowser2 protocol.\r
+ //\r
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &FormBrowser2);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Private = AllocateZeroPool (sizeof (VARIABLE_CLEANUP_HII_PRIVATE_DATA));\r
+ if (Private == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ Private->Signature = VARIABLE_CLEANUP_HII_PRIVATE_SIGNATURE;\r
+ Private->ConfigAccess.ExtractConfig = VariableCleanupHiiExtractConfig;\r
+ Private->ConfigAccess.RouteConfig = VariableCleanupHiiRouteConfig;\r
+ Private->ConfigAccess.Callback = VariableCleanupHiiCallback;\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiHiiConfigRoutingProtocolGuid,\r
+ NULL,\r
+ (VOID **) &Private->ConfigRouting\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Install Device Path Protocol and Config Access protocol to driver handle.\r
+ //\r
+ Status = gBS->InstallMultipleProtocolInterfaces (\r
+ &Private->DriverHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ &mVarCleanupHiiVendorDevicePath,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ &Private->ConfigAccess,\r
+ NULL\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ goto Done;\r
+ }\r
+\r
+ //\r
+ // Publish our HII data.\r
+ //\r
+ Private->HiiHandle = HiiAddPackages (\r
+ &mVariableCleanupHiiGuid,\r
+ Private->DriverHandle,\r
+ PlatformVarCleanupLibStrings,\r
+ PlatVarCleanupBin,\r
+ NULL\r
+ );\r
+ if (Private->HiiHandle == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ goto Done;\r
+ }\r
+\r
+ UpdateUserVariableForm (Private);\r
+\r
+ Status = FormBrowser2->SendForm (\r
+ FormBrowser2,\r
+ &Private->HiiHandle,\r
+ 1,\r
+ NULL,\r
+ 0,\r
+ NULL,\r
+ NULL\r
+ );\r
+ break;\r
+\r
+ default:\r
+ return EFI_UNSUPPORTED;\r
+ break;\r
+ }\r
+\r
+Done:\r
+ if (Private->DriverHandle != NULL) {\r
+ gBS->UninstallMultipleProtocolInterfaces (\r
+ Private->DriverHandle,\r
+ &gEfiDevicePathProtocolGuid,\r
+ &mVarCleanupHiiVendorDevicePath,\r
+ &gEfiHiiConfigAccessProtocolGuid,\r
+ &Private->ConfigAccess,\r
+ NULL\r
+ );\r
+ }\r
+ if (Private->HiiHandle != NULL) {\r
+ HiiRemovePackages (Private->HiiHandle);\r
+ }\r
+\r
+ FreePool (Private);\r
+\r
+ //\r
+ // Destroyed the created user variable nodes\r
+ //\r
+ DestroyUserVariableNode ();\r
+ return Status;\r
+}\r
+\r
+/**\r
+ Get last boot variable error flag.\r
+\r
+ @return Last boot variable error flag.\r
+\r
+**/\r
+VAR_ERROR_FLAG\r
+EFIAPI\r
+GetLastBootVarErrorFlag (\r
+ )\r
+{\r
+ return mLastVarErrorFlag;\r
+}\r
+\r
+/**\r
+ Notification function of END_OF_DXE.\r
+\r
+ This is a notification function registered on END_OF_DXE event.\r
+\r
+ @param[in] Event Event whose notification function is being invoked.\r
+ @param[in] Context Pointer to the notification function's context.\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+PlatformVarCleanupEndOfDxeEvent (\r
+ IN EFI_EVENT Event,\r
+ IN VOID *Context\r
+ )\r
+{\r
+ mEndOfDxe = TRUE;\r
+}\r
+\r
+/**\r
+ The constructor function caches the pointer to VarCheck protocol and last boot variable error flag.\r
+\r
+ The constructor function locates VarCheck protocol from protocol database.\r
+ It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.\r
+\r
+ @param ImageHandle The firmware allocated handle for the EFI image.\r
+ @param SystemTable A pointer to the EFI System Table.\r
+\r
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PlatformVarCleanupLibConstructor (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Event;\r
+\r
+ mLastVarErrorFlag = InternalGetVarErrorFlag ();\r
+ DEBUG ((EFI_D_INFO, "mLastVarErrorFlag - 0x%02x\n", mLastVarErrorFlag));\r
+\r
+ Status = gBS->LocateProtocol (\r
+ &gEdkiiVarCheckProtocolGuid,\r
+ NULL,\r
+ (VOID **) &mVarCheck\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Register EFI_END_OF_DXE_EVENT_GROUP_GUID event.\r
+ //\r
+ Status = gBS->CreateEventEx (\r
+ EVT_NOTIFY_SIGNAL,\r
+ TPL_CALLBACK,\r
+ PlatformVarCleanupEndOfDxeEvent,\r
+ NULL,\r
+ &gEfiEndOfDxeEventGroupGuid,\r
+ &Event\r
+ );\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r