| /** @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; | |
| } |