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