When OVMF tried to restore the variables from the file-based NvVars, it failed to set the read-only variable and aborted the restoration with this message: Variable Check ReadOnly variable fail Write Protected - 04B37FE8-F6AE-480B-BDD5-37D98C5E89AA:VarErrorFlag Since it's a read-only variable maintained by the firmware, it's pointless to restore the previous value, so the check can be relaxed to allow EFI_WRITE_PROTECTED returned from SetVariable. Cc: Laszlo Ersek <lersek@redhat.com> Cc: Jordan Justen <jordan.l.justen@intel.com> Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Gary Lin <glin@suse.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com>
		
			
				
	
	
		
			876 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			876 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Serialize Variables Library implementation
 | 
						|
 | 
						|
  Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
 | 
						|
  This program and the accompanying materials
 | 
						|
  are licensed and made available under the terms and conditions of the BSD License
 | 
						|
  which accompanies this distribution.  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.php
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "SerializeVariablesLib.h"
 | 
						|
 | 
						|
/**
 | 
						|
  Serialization format:
 | 
						|
 | 
						|
  The SerializeVariablesLib interface does not specify a format
 | 
						|
  for the serialization of the variable data.  This library uses
 | 
						|
  a packed array of a non-uniformly sized data structure elements.
 | 
						|
 | 
						|
  Each variable is stored (packed) as:
 | 
						|
    UINT32   VendorNameSize;  // Name size in bytes
 | 
						|
    CHAR16   VendorName[?];   // The variable unicode name including the
 | 
						|
                              // null terminating character.
 | 
						|
    EFI_GUID VendorGuid;      // The variable GUID
 | 
						|
    UINT32   DataSize;        // The size of variable data in bytes
 | 
						|
    UINT8    Data[?];         // The variable data
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Unpacks the next variable from the buffer
 | 
						|
 | 
						|
  @param[in]  Buffer - Buffer pointing to the next variable instance
 | 
						|
                On subsequent calls, the pointer should be incremented
 | 
						|
                by the returned SizeUsed value.
 | 
						|
  @param[in]  MaxSize - Max allowable size for the variable data
 | 
						|
                On subsequent calls, this should be decremented
 | 
						|
                by the returned SizeUsed value.
 | 
						|
  @param[out] Name - Variable name string (address in Buffer)
 | 
						|
  @param[out] NameSize - Size of Name in bytes
 | 
						|
  @param[out] Guid - GUID of variable (address in Buffer)
 | 
						|
  @param[out] Attributes - Attributes of variable
 | 
						|
  @param[out] Data - Buffer containing Data for variable (address in Buffer)
 | 
						|
  @param[out] DataSize - Size of Data in bytes
 | 
						|
  @param[out] SizeUsed - Total size used for this variable instance in Buffer
 | 
						|
 | 
						|
  @return     EFI_STATUS based on the success or failure of the operation
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
UnpackVariableFromBuffer (
 | 
						|
  IN  VOID     *Buffer,
 | 
						|
  IN  UINTN    MaxSize,
 | 
						|
  OUT CHAR16   **Name,
 | 
						|
  OUT UINT32   *NameSize,
 | 
						|
  OUT EFI_GUID **Guid,
 | 
						|
  OUT UINT32   *Attributes,
 | 
						|
  OUT UINT32   *DataSize,
 | 
						|
  OUT VOID     **Data,
 | 
						|
  OUT UINTN    *SizeUsed
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT8  *BytePtr;
 | 
						|
  UINTN  Offset;
 | 
						|
 | 
						|
  BytePtr = (UINT8*)Buffer;
 | 
						|
  Offset = 0;
 | 
						|
 | 
						|
  *NameSize = *(UINT32*) (BytePtr + Offset);
 | 
						|
  Offset = Offset + sizeof (UINT32);
 | 
						|
 | 
						|
  if (Offset > MaxSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *Name = (CHAR16*) (BytePtr + Offset);
 | 
						|
  Offset = Offset + *(UINT32*)BytePtr;
 | 
						|
  if (Offset > MaxSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *Guid = (EFI_GUID*) (BytePtr + Offset);
 | 
						|
  Offset = Offset + sizeof (EFI_GUID);
 | 
						|
  if (Offset > MaxSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *Attributes = *(UINT32*) (BytePtr + Offset);
 | 
						|
  Offset = Offset + sizeof (UINT32);
 | 
						|
  if (Offset > MaxSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *DataSize = *(UINT32*) (BytePtr + Offset);
 | 
						|
  Offset = Offset + sizeof (UINT32);
 | 
						|
  if (Offset > MaxSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *Data = (VOID*) (BytePtr + Offset);
 | 
						|
  Offset = Offset + *DataSize;
 | 
						|
  if (Offset > MaxSize) {
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *SizeUsed = Offset;
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Iterates through the variables in the buffer, and calls a callback
 | 
						|
  function for each variable found.
 | 
						|
 | 
						|
  @param[in]  CallbackFunction - Function called for each variable instance
 | 
						|
  @param[in]  Context - Passed to each call of CallbackFunction
 | 
						|
  @param[in]  Buffer - Buffer containing serialized variables
 | 
						|
  @param[in]  MaxSize - Size of Buffer in bytes
 | 
						|
 | 
						|
  @return     EFI_STATUS based on the success or failure of the operation
 | 
						|
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
EFI_STATUS
 | 
						|
IterateVariablesInBuffer (
 | 
						|
  IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK  CallbackFunction,
 | 
						|
  IN VOID                                       *CallbackContext,
 | 
						|
  IN VOID                                       *Buffer,
 | 
						|
  IN UINTN                                      MaxSize
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS Status;
 | 
						|
  UINTN         TotalSizeUsed;
 | 
						|
  UINTN         SizeUsed;
 | 
						|
 | 
						|
  CHAR16        *Name;
 | 
						|
  UINT32        NameSize;
 | 
						|
  CHAR16        *AlignedName;
 | 
						|
  UINT32        AlignedNameMaxSize;
 | 
						|
  EFI_GUID      *Guid;
 | 
						|
  UINT32        Attributes;
 | 
						|
  UINT32        DataSize;
 | 
						|
  VOID          *Data;
 | 
						|
 | 
						|
  SizeUsed = 0;
 | 
						|
  AlignedName = NULL;
 | 
						|
  AlignedNameMaxSize = 0;
 | 
						|
  Name = NULL;
 | 
						|
  Guid = NULL;
 | 
						|
  Attributes = 0;
 | 
						|
  DataSize = 0;
 | 
						|
  Data = NULL;
 | 
						|
 | 
						|
  for (
 | 
						|
    Status = EFI_SUCCESS, TotalSizeUsed = 0;
 | 
						|
    !EFI_ERROR (Status) && (TotalSizeUsed < MaxSize);
 | 
						|
    ) {
 | 
						|
    Status = UnpackVariableFromBuffer (
 | 
						|
               (VOID*) ((UINT8*) Buffer + TotalSizeUsed),
 | 
						|
               (MaxSize - TotalSizeUsed),
 | 
						|
               &Name,
 | 
						|
               &NameSize,
 | 
						|
               &Guid,
 | 
						|
               &Attributes,
 | 
						|
               &DataSize,
 | 
						|
               &Data,
 | 
						|
               &SizeUsed
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      return Status;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // We copy the name to a separately allocated buffer,
 | 
						|
    // to be sure it is 16-bit aligned.
 | 
						|
    //
 | 
						|
    if (NameSize > AlignedNameMaxSize) {
 | 
						|
      if (AlignedName != NULL) {
 | 
						|
        FreePool (AlignedName);
 | 
						|
      }
 | 
						|
      AlignedName = AllocatePool (NameSize);
 | 
						|
    }
 | 
						|
    if (AlignedName == NULL) {
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
    CopyMem (AlignedName, Name, NameSize);
 | 
						|
 | 
						|
    TotalSizeUsed = TotalSizeUsed + SizeUsed;
 | 
						|
 | 
						|
    //
 | 
						|
    // Run the callback function
 | 
						|
    //
 | 
						|
    Status = (*CallbackFunction) (
 | 
						|
               CallbackContext,
 | 
						|
               AlignedName,
 | 
						|
               Guid,
 | 
						|
               Attributes,
 | 
						|
               DataSize,
 | 
						|
               Data
 | 
						|
               );
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  if (AlignedName != NULL) {
 | 
						|
    FreePool (AlignedName);
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Make sure the entire buffer was used, or else return an error
 | 
						|
  //
 | 
						|
  if (TotalSizeUsed != MaxSize) {
 | 
						|
    DEBUG ((
 | 
						|
      EFI_D_ERROR,
 | 
						|
      "Deserialize variables error: TotalSizeUsed(%Lu) != MaxSize(%Lu)\n",
 | 
						|
      (UINT64)TotalSizeUsed,
 | 
						|
      (UINT64)MaxSize
 | 
						|
      ));
 | 
						|
    return EFI_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
STATIC
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
IterateVariablesCallbackNop (
 | 
						|
  IN  VOID                         *Context,
 | 
						|
  IN  CHAR16                       *VariableName,
 | 
						|
  IN  EFI_GUID                     *VendorGuid,
 | 
						|
  IN  UINT32                       Attributes,
 | 
						|
  IN  UINTN                        DataSize,
 | 
						|
  IN  VOID                         *Data
 | 
						|
  )
 | 
						|
{
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
STATIC
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
IterateVariablesCallbackSetInInstance (
 | 
						|
  IN  VOID                         *Context,
 | 
						|
  IN  CHAR16                       *VariableName,
 | 
						|
  IN  EFI_GUID                     *VendorGuid,
 | 
						|
  IN  UINT32                       Attributes,
 | 
						|
  IN  UINTN                        DataSize,
 | 
						|
  IN  VOID                         *Data
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_HANDLE  Instance;
 | 
						|
 | 
						|
  Instance = (EFI_HANDLE) Context;
 | 
						|
 | 
						|
  return SerializeVariablesAddVariable (
 | 
						|
           Instance,
 | 
						|
           VariableName,
 | 
						|
           VendorGuid,
 | 
						|
           Attributes,
 | 
						|
           DataSize,
 | 
						|
           Data
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
STATIC
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
IterateVariablesCallbackSetSystemVariable (
 | 
						|
  IN  VOID                         *Context,
 | 
						|
  IN  CHAR16                       *VariableName,
 | 
						|
  IN  EFI_GUID                     *VendorGuid,
 | 
						|
  IN  UINT32                       Attributes,
 | 
						|
  IN  UINTN                        DataSize,
 | 
						|
  IN  VOID                         *Data
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS          Status;
 | 
						|
  STATIC CONST UINT32 AuthMask =
 | 
						|
                        EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS |
 | 
						|
                        EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;
 | 
						|
 | 
						|
  Status = gRT->SetVariable (
 | 
						|
             VariableName,
 | 
						|
             VendorGuid,
 | 
						|
             Attributes,
 | 
						|
             DataSize,
 | 
						|
             Data
 | 
						|
             );
 | 
						|
 | 
						|
  if (Status == EFI_SECURITY_VIOLATION && (Attributes & AuthMask) != 0) {
 | 
						|
    DEBUG ((DEBUG_WARN, "%a: setting authenticated variable \"%s\" "
 | 
						|
            "failed with EFI_SECURITY_VIOLATION, ignoring\n", __FUNCTION__,
 | 
						|
            VariableName));
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  } else if (Status == EFI_WRITE_PROTECTED) {
 | 
						|
    DEBUG ((DEBUG_WARN, "%a: setting ReadOnly variable \"%s\" "
 | 
						|
            "failed with EFI_WRITE_PROTECTED, ignoring\n", __FUNCTION__,
 | 
						|
            VariableName));
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
STATIC
 | 
						|
RETURN_STATUS
 | 
						|
EnsureExtraBufferSpace (
 | 
						|
  IN  SV_INSTANCE  *Instance,
 | 
						|
  IN  UINTN        Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID *NewBuffer;
 | 
						|
  UINTN NewSize;
 | 
						|
 | 
						|
  NewSize = Instance->DataSize + Size;
 | 
						|
  if (NewSize <= Instance->BufferSize) {
 | 
						|
    return RETURN_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Double the required size to lessen the need to re-allocate in the future
 | 
						|
  //
 | 
						|
  NewSize = 2 * NewSize;
 | 
						|
 | 
						|
  NewBuffer = AllocatePool (NewSize);
 | 
						|
  if (NewBuffer == NULL) {
 | 
						|
    return RETURN_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Instance->BufferPtr != NULL) {
 | 
						|
    CopyMem (NewBuffer, Instance->BufferPtr, Instance->DataSize);
 | 
						|
    FreePool (Instance->BufferPtr);
 | 
						|
  }
 | 
						|
 | 
						|
  Instance->BufferPtr = NewBuffer;
 | 
						|
  Instance->BufferSize = NewSize;
 | 
						|
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
AppendToBuffer (
 | 
						|
  IN  SV_INSTANCE  *Instance,
 | 
						|
  IN  VOID         *Data,
 | 
						|
  IN  UINTN        Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN NewSize;
 | 
						|
 | 
						|
  ASSERT (Instance != NULL);
 | 
						|
  ASSERT (Data != NULL);
 | 
						|
 | 
						|
  NewSize = Instance->DataSize + Size;
 | 
						|
  ASSERT ((Instance->DataSize + Size) <= Instance->BufferSize);
 | 
						|
 | 
						|
  CopyMem (
 | 
						|
    (VOID*) (((UINT8*) (Instance->BufferPtr)) + Instance->DataSize),
 | 
						|
    Data,
 | 
						|
    Size
 | 
						|
    );
 | 
						|
 | 
						|
  Instance->DataSize = NewSize;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Creates a new variable serialization instance
 | 
						|
 | 
						|
  @param[out]  Handle - Handle for a variable serialization instance
 | 
						|
 | 
						|
  @retval      RETURN_SUCCESS - The variable serialization instance was
 | 
						|
                 successfully created.
 | 
						|
  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
 | 
						|
                 create the variable serialization instance.
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
SerializeVariablesNewInstance (
 | 
						|
  OUT EFI_HANDLE                      *Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  SV_INSTANCE  *New;
 | 
						|
 | 
						|
  New = AllocateZeroPool (sizeof (*New));
 | 
						|
  if (New == NULL) {
 | 
						|
    return RETURN_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  New->Signature = SV_SIGNATURE;
 | 
						|
 | 
						|
  *Handle = (EFI_HANDLE) New;
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Free memory associated with a variable serialization instance
 | 
						|
 | 
						|
  @param[in]  Handle - Handle for a variable serialization instance
 | 
						|
 | 
						|
  @retval      RETURN_SUCCESS - The variable serialization instance was
 | 
						|
                 successfully freed.
 | 
						|
  @retval      RETURN_INVALID_PARAMETER - Handle was not a valid
 | 
						|
                 variable serialization instance.
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
SerializeVariablesFreeInstance (
 | 
						|
  IN EFI_HANDLE Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  SV_INSTANCE    *Instance;
 | 
						|
 | 
						|
  Instance = SV_FROM_HANDLE (Handle);
 | 
						|
 | 
						|
  if (Instance->Signature != SV_SIGNATURE) {
 | 
						|
    return RETURN_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  Instance->Signature = 0;
 | 
						|
 | 
						|
  if (Instance->BufferPtr != NULL) {
 | 
						|
    FreePool (Instance->BufferPtr);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (Instance);
 | 
						|
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Creates a new variable serialization instance using the given
 | 
						|
  binary representation of the variables to fill the new instance
 | 
						|
 | 
						|
  @param[out] Handle - Handle for a variable serialization instance
 | 
						|
  @param[in]  Buffer - A buffer with the serialized representation
 | 
						|
                of the variables.  Must be the same format as produced
 | 
						|
                by SerializeVariablesToBuffer.
 | 
						|
  @param[in]  Size - This is the size of the binary representation
 | 
						|
                of the variables.
 | 
						|
 | 
						|
  @retval      RETURN_SUCCESS - The binary representation was successfully
 | 
						|
                 imported into a new variable serialization instance
 | 
						|
  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
 | 
						|
                 create the new variable serialization instance
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
SerializeVariablesNewInstanceFromBuffer (
 | 
						|
  OUT EFI_HANDLE                          *Handle,
 | 
						|
  IN  VOID                                *Buffer,
 | 
						|
  IN  UINTN                               Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS Status;
 | 
						|
 | 
						|
  Status = SerializeVariablesNewInstance (Handle);
 | 
						|
  if (RETURN_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = IterateVariablesInBuffer (
 | 
						|
             IterateVariablesCallbackNop,
 | 
						|
             NULL,
 | 
						|
             Buffer,
 | 
						|
             Size
 | 
						|
             );
 | 
						|
  if (RETURN_ERROR (Status)) {
 | 
						|
    SerializeVariablesFreeInstance (*Handle);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = IterateVariablesInBuffer (
 | 
						|
             IterateVariablesCallbackSetInInstance,
 | 
						|
             (VOID*) *Handle,
 | 
						|
             Buffer,
 | 
						|
             Size
 | 
						|
             );
 | 
						|
  if (RETURN_ERROR (Status)) {
 | 
						|
    SerializeVariablesFreeInstance (*Handle);
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Iterates all variables found with RuntimeServices GetNextVariableName
 | 
						|
 | 
						|
  @param[in]   CallbackFunction - Function called for each variable instance
 | 
						|
  @param[in]   Context - Passed to each call of CallbackFunction
 | 
						|
 | 
						|
  @retval      RETURN_SUCCESS - All variables were iterated without the
 | 
						|
                 CallbackFunction returning an error
 | 
						|
  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
 | 
						|
                 iterate through the variables
 | 
						|
  @return      Any of RETURN_ERROR indicates an error reading the variable
 | 
						|
                 or an error was returned from CallbackFunction
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
SerializeVariablesIterateSystemVariables (
 | 
						|
  IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction,
 | 
						|
  IN VOID                                      *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS               Status;
 | 
						|
  UINTN                       VariableNameBufferSize;
 | 
						|
  UINTN                       VariableNameSize;
 | 
						|
  CHAR16                      *VariableName;
 | 
						|
  EFI_GUID                    VendorGuid;
 | 
						|
  UINTN                       VariableDataBufferSize;
 | 
						|
  UINTN                       VariableDataSize;
 | 
						|
  VOID                        *VariableData;
 | 
						|
  UINT32                      VariableAttributes;
 | 
						|
  VOID                        *NewBuffer;
 | 
						|
 | 
						|
  //
 | 
						|
  // Initialize the variable name and data buffer variables.
 | 
						|
  //
 | 
						|
  VariableNameBufferSize = sizeof (CHAR16);
 | 
						|
  VariableName = AllocateZeroPool (VariableNameBufferSize);
 | 
						|
 | 
						|
  VariableDataBufferSize = 0;
 | 
						|
  VariableData = NULL;
 | 
						|
 | 
						|
  for (;;) {
 | 
						|
    //
 | 
						|
    // Get the next variable name and guid
 | 
						|
    //
 | 
						|
    VariableNameSize = VariableNameBufferSize;
 | 
						|
    Status = gRT->GetNextVariableName (
 | 
						|
                    &VariableNameSize,
 | 
						|
                    VariableName,
 | 
						|
                    &VendorGuid
 | 
						|
                    );
 | 
						|
    if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
      //
 | 
						|
      // The currently allocated VariableName buffer is too small,
 | 
						|
      // so we allocate a larger buffer, and copy the old buffer
 | 
						|
      // to it.
 | 
						|
      //
 | 
						|
      NewBuffer = AllocatePool (VariableNameSize);
 | 
						|
      if (NewBuffer == NULL) {
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      CopyMem (NewBuffer, VariableName, VariableNameBufferSize);
 | 
						|
      if (VariableName != NULL) {
 | 
						|
        FreePool (VariableName);
 | 
						|
      }
 | 
						|
      VariableName = NewBuffer;
 | 
						|
      VariableNameBufferSize = VariableNameSize;
 | 
						|
 | 
						|
      //
 | 
						|
      // Try to get the next variable name again with the larger buffer.
 | 
						|
      //
 | 
						|
      Status = gRT->GetNextVariableName (
 | 
						|
                      &VariableNameSize,
 | 
						|
                      VariableName,
 | 
						|
                      &VendorGuid
 | 
						|
                      );
 | 
						|
    }
 | 
						|
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      if (Status == EFI_NOT_FOUND) {
 | 
						|
        Status = EFI_SUCCESS;
 | 
						|
      }
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Get the variable data and attributes
 | 
						|
    //
 | 
						|
    VariableDataSize = VariableDataBufferSize;
 | 
						|
    Status = gRT->GetVariable (
 | 
						|
                    VariableName,
 | 
						|
                    &VendorGuid,
 | 
						|
                    &VariableAttributes,
 | 
						|
                    &VariableDataSize,
 | 
						|
                    VariableData
 | 
						|
                    );
 | 
						|
    if (Status == EFI_BUFFER_TOO_SMALL) {
 | 
						|
      //
 | 
						|
      // The currently allocated VariableData buffer is too small,
 | 
						|
      // so we allocate a larger buffer.
 | 
						|
      //
 | 
						|
      if (VariableDataBufferSize != 0) {
 | 
						|
        FreePool (VariableData);
 | 
						|
        VariableData = NULL;
 | 
						|
        VariableDataBufferSize = 0;
 | 
						|
      }
 | 
						|
      VariableData = AllocatePool (VariableDataSize);
 | 
						|
      if (VariableData == NULL) {
 | 
						|
        Status = EFI_OUT_OF_RESOURCES;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
      VariableDataBufferSize = VariableDataSize;
 | 
						|
 | 
						|
      //
 | 
						|
      // Try to read the variable again with the larger buffer.
 | 
						|
      //
 | 
						|
      Status = gRT->GetVariable (
 | 
						|
                      VariableName,
 | 
						|
                      &VendorGuid,
 | 
						|
                      &VariableAttributes,
 | 
						|
                      &VariableDataSize,
 | 
						|
                      VariableData
 | 
						|
                      );
 | 
						|
    }
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Run the callback function
 | 
						|
    //
 | 
						|
    Status = (*CallbackFunction) (
 | 
						|
               Context,
 | 
						|
               VariableName,
 | 
						|
               &VendorGuid,
 | 
						|
               VariableAttributes,
 | 
						|
               VariableDataSize,
 | 
						|
               VariableData
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  if (VariableName != NULL) {
 | 
						|
    FreePool (VariableName);
 | 
						|
  }
 | 
						|
 | 
						|
  if (VariableData != NULL) {
 | 
						|
    FreePool (VariableData);
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Iterates all variables found in the variable serialization instance
 | 
						|
 | 
						|
  @param[in]   Handle - Handle for a variable serialization instance
 | 
						|
  @param[in]   CallbackFunction - Function called for each variable instance
 | 
						|
  @param[in]   Context - Passed to each call of CallbackFunction
 | 
						|
 | 
						|
  @retval      RETURN_SUCCESS - All variables were iterated without the
 | 
						|
                 CallbackFunction returning an error
 | 
						|
  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
 | 
						|
                 iterate through the variables
 | 
						|
  @return      Any of RETURN_ERROR indicates an error reading the variable
 | 
						|
                 or an error was returned from CallbackFunction
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
SerializeVariablesIterateInstanceVariables (
 | 
						|
  IN EFI_HANDLE                                Handle,
 | 
						|
  IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction,
 | 
						|
  IN VOID                                      *Context
 | 
						|
  )
 | 
						|
{
 | 
						|
  SV_INSTANCE    *Instance;
 | 
						|
 | 
						|
  Instance = SV_FROM_HANDLE (Handle);
 | 
						|
 | 
						|
  if ((Instance->BufferPtr != NULL) && (Instance->DataSize != 0)) {
 | 
						|
    return IterateVariablesInBuffer (
 | 
						|
             CallbackFunction,
 | 
						|
             Context,
 | 
						|
             Instance->BufferPtr,
 | 
						|
             Instance->DataSize
 | 
						|
             );
 | 
						|
  } else {
 | 
						|
    return RETURN_SUCCESS;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Sets all variables found in the variable serialization instance
 | 
						|
 | 
						|
  @param[in]   Handle - Handle for a variable serialization instance
 | 
						|
 | 
						|
  @retval      RETURN_SUCCESS - All variables were set successfully
 | 
						|
  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
 | 
						|
                 set all the variables
 | 
						|
  @return      Any of RETURN_ERROR indicates an error reading the variables
 | 
						|
                 or in attempting to set a variable
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
SerializeVariablesSetSerializedVariables (
 | 
						|
  IN EFI_HANDLE                       Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  return SerializeVariablesIterateInstanceVariables (
 | 
						|
           Handle,
 | 
						|
           IterateVariablesCallbackSetSystemVariable,
 | 
						|
           NULL
 | 
						|
           );
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Adds a variable to the variable serialization instance
 | 
						|
 | 
						|
  @param[in] Handle - Handle for a variable serialization instance
 | 
						|
  @param[in] VariableName - Refer to RuntimeServices GetVariable
 | 
						|
  @param[in] VendorGuid - Refer to RuntimeServices GetVariable
 | 
						|
  @param[in] Attributes - Refer to RuntimeServices GetVariable
 | 
						|
  @param[in] DataSize - Refer to RuntimeServices GetVariable
 | 
						|
  @param[in] Data - Refer to RuntimeServices GetVariable
 | 
						|
 | 
						|
  @retval      RETURN_SUCCESS - All variables were set successfully
 | 
						|
  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
 | 
						|
                 add the variable
 | 
						|
  @retval      RETURN_INVALID_PARAMETER - Handle was not a valid
 | 
						|
                 variable serialization instance or
 | 
						|
                 VariableName, VariableGuid or Data are NULL.
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
SerializeVariablesAddVariable (
 | 
						|
  IN EFI_HANDLE                   Handle,
 | 
						|
  IN CHAR16                       *VariableName,
 | 
						|
  IN EFI_GUID                     *VendorGuid,
 | 
						|
  IN UINT32                       Attributes,
 | 
						|
  IN UINTN                        DataSize,
 | 
						|
  IN VOID                         *Data
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS  Status;
 | 
						|
  SV_INSTANCE    *Instance;
 | 
						|
  UINT32         SerializedNameSize;
 | 
						|
  UINT32         SerializedDataSize;
 | 
						|
  UINTN          SerializedSize;
 | 
						|
 | 
						|
  Instance = SV_FROM_HANDLE (Handle);
 | 
						|
 | 
						|
  if ((Instance->Signature != SV_SIGNATURE) ||
 | 
						|
      (VariableName == NULL) || (VendorGuid == NULL) || (Data == NULL)) {
 | 
						|
  }
 | 
						|
 | 
						|
  SerializedNameSize = (UINT32) StrSize (VariableName);
 | 
						|
 | 
						|
  SerializedSize =
 | 
						|
    sizeof (SerializedNameSize) +
 | 
						|
    SerializedNameSize +
 | 
						|
    sizeof (*VendorGuid) +
 | 
						|
    sizeof (Attributes) +
 | 
						|
    sizeof (SerializedDataSize) +
 | 
						|
    DataSize;
 | 
						|
 | 
						|
  Status = EnsureExtraBufferSpace (
 | 
						|
             Instance,
 | 
						|
             SerializedSize
 | 
						|
             );
 | 
						|
  if (RETURN_ERROR (Status)) {
 | 
						|
    return Status;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Add name size (UINT32)
 | 
						|
  //
 | 
						|
  AppendToBuffer (Instance, (VOID*) &SerializedNameSize, sizeof (SerializedNameSize));
 | 
						|
 | 
						|
  //
 | 
						|
  // Add variable unicode name string
 | 
						|
  //
 | 
						|
  AppendToBuffer (Instance, (VOID*) VariableName, SerializedNameSize);
 | 
						|
 | 
						|
  //
 | 
						|
  // Add variable GUID
 | 
						|
  //
 | 
						|
  AppendToBuffer (Instance, (VOID*) VendorGuid, sizeof (*VendorGuid));
 | 
						|
 | 
						|
  //
 | 
						|
  // Add variable attributes
 | 
						|
  //
 | 
						|
  AppendToBuffer (Instance, (VOID*) &Attributes, sizeof (Attributes));
 | 
						|
 | 
						|
  //
 | 
						|
  // Add variable data size (UINT32)
 | 
						|
  //
 | 
						|
  SerializedDataSize = (UINT32) DataSize;
 | 
						|
  AppendToBuffer (Instance, (VOID*) &SerializedDataSize, sizeof (SerializedDataSize));
 | 
						|
 | 
						|
  //
 | 
						|
  // Add variable data
 | 
						|
  //
 | 
						|
  AppendToBuffer (Instance, Data, DataSize);
 | 
						|
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/**
 | 
						|
  Serializes the variables known to this instance into the
 | 
						|
  provided buffer.
 | 
						|
 | 
						|
  @param[in]     Handle - Handle for a variable serialization instance
 | 
						|
  @param[out]    Buffer - A buffer to store the binary representation
 | 
						|
                   of the variables.
 | 
						|
  @param[in,out] Size - On input this is the size of the buffer.
 | 
						|
                   On output this is the size of the binary representation
 | 
						|
                   of the variables.
 | 
						|
 | 
						|
  @retval      RETURN_SUCCESS - The binary representation was successfully
 | 
						|
                 completed and returned in the buffer.
 | 
						|
  @retval      RETURN_OUT_OF_RESOURCES - There we not enough resources to
 | 
						|
                 save the variables to the buffer.
 | 
						|
  @retval      RETURN_INVALID_PARAMETER - Handle was not a valid
 | 
						|
                 variable serialization instance or
 | 
						|
                 Size or Buffer were NULL.
 | 
						|
  @retval      RETURN_BUFFER_TOO_SMALL - The Buffer size as indicated by
 | 
						|
                 the Size parameter was too small for the serialized
 | 
						|
                 variable data.  Size is returned with the required size.
 | 
						|
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
SerializeVariablesToBuffer (
 | 
						|
  IN     EFI_HANDLE                       Handle,
 | 
						|
  OUT    VOID                             *Buffer,
 | 
						|
  IN OUT UINTN                            *Size
 | 
						|
  )
 | 
						|
{
 | 
						|
  SV_INSTANCE    *Instance;
 | 
						|
 | 
						|
  Instance = SV_FROM_HANDLE (Handle);
 | 
						|
 | 
						|
  if (Size == NULL) {
 | 
						|
    return RETURN_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  if (*Size < Instance->DataSize) {
 | 
						|
    *Size = Instance->DataSize;
 | 
						|
    return RETURN_BUFFER_TOO_SMALL;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Buffer == NULL) {
 | 
						|
    return RETURN_INVALID_PARAMETER;
 | 
						|
  }
 | 
						|
 | 
						|
  *Size = Instance->DataSize;
 | 
						|
  CopyMem (Buffer, Instance->BufferPtr, Instance->DataSize);
 | 
						|
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 | 
						|
 |