/** @file | |
Serialize Variables Library implementation | |
Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#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 (( | |
DEBUG_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", | |
__func__, | |
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", | |
__func__, | |
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; | |
} |