https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
		
			
				
	
	
		
			1275 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1275 lines
		
	
	
		
			43 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @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 ((EFI_D_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 ((EFI_D_INFO, "PlatformVarCleanup - User variable: %g:%s\n", Guid, Name));
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
| //  DEBUG ((EFI_D_INFO, "PlatformVarCleanup - Variable Property: %g:%s\n", Guid, Name));
 | |
| //  DEBUG ((EFI_D_INFO, "  Revision  - 0x%04x\n", Property.Revision));
 | |
| //  DEBUG ((EFI_D_INFO, "  Property  - 0x%04x\n", Property.Property));
 | |
| //  DEBUG ((EFI_D_INFO, "  Attribute - 0x%08x\n", Property.Attributes));
 | |
| //  DEBUG ((EFI_D_INFO, "  MinSize   - 0x%x\n", Property.MinSize));
 | |
| //  DEBUG ((EFI_D_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 ((EFI_D_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 ((EFI_D_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 ((EFI_D_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->HiiHandle);
 | |
|     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 ((EFI_D_ERROR, "NOTICE - VAR_ERROR_FLAG_SYSTEM_ERROR\n"));
 | |
|     DEBUG ((EFI_D_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 ((EFI_D_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;
 | |
| }
 |