The HiiConstructConfigHdr() function takes the "DriverHandle" parameter in order to fetch the device path from it, and then turn the device path into PATH routing information. The HiiConstructConfigHdr() function is called from VariableCleanupHiiExtractConfig(), which is only installed when "Type" is "VarCleanupManually" in PlatformVarCleanup(). In that case, we create "Private->DriverHandle" as a new handle, and install "mVarCleanupHiiVendorDevicePath" on it. Then we pass "Private->DriverHandle" to HiiAddPackages(), which consumes the device path for routing purposes. It follows that the "DriverHandle" argument passed to HiiConstructConfigHdr() should be the same driver handle, for matching routing. Currently we pass "Private->HiiHandle", which is clearly a typo, because it is the return value of HiiAddPackages(), and stands for the published HII package list. Therefore this patch addresses an actual bug. The typo has not been flagged by compilers because the UEFI spec regrettably defines both EFI_HANDLE and EFI_HII_HANDLE as (VOID*). Cc: Hao A Wu <hao.a.wu@intel.com> Cc: Jian J Wang <jian.j.wang@intel.com> Cc: Liming Gao <liming.gao@intel.com> Signed-off-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> Reviewed-by: Hao A Wu <hao.a.wu@intel.com>
		
			
				
	
	
		
			1279 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1279 lines
		
	
	
		
			44 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->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 ((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;
 | |
| }
 |