2 Serialize Variables Library implementation
4 Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "SerializeVariablesLib.h"
20 The SerializeVariablesLib interface does not specify a format
21 for the serialization of the variable data. This library uses
22 a packed array of a non-uniformly sized data structure elements.
24 Each variable is stored (packed) as:
25 UINT32 VendorNameSize; // Name size in bytes
26 CHAR16 VendorName[?]; // The variable unicode name including the
27 // null terminating character.
28 EFI_GUID VendorGuid; // The variable GUID
29 UINT32 DataSize; // The size of variable data in bytes
30 UINT8 Data[?]; // The variable data
36 Unpacks the next variable from the buffer
38 @param[in] Buffer - Buffer pointing to the next variable instance
39 On subsequent calls, the pointer should be incremented
40 by the returned SizeUsed value.
41 @param[in] MaxSize - Max allowable size for the variable data
42 On subsequent calls, this should be decremented
43 by the returned SizeUsed value.
44 @param[out] Name - Variable name string (address in Buffer)
45 @param[out] NameSize - Size of Name in bytes
46 @param[out] Guid - GUID of variable (address in Buffer)
47 @param[out] Attributes - Attributes of variable
48 @param[out] Data - Buffer containing Data for variable (address in Buffer)
49 @param[out] DataSize - Size of Data in bytes
50 @param[out] SizeUsed - Total size used for this variable instance in Buffer
52 @return EFI_STATUS based on the success or failure of the operation
57 UnpackVariableFromBuffer (
63 OUT UINT32
*Attributes
,
72 BytePtr
= (UINT8
*)Buffer
;
75 *NameSize
= *(UINT32
*) (BytePtr
+ Offset
);
76 Offset
= Offset
+ sizeof (UINT32
);
78 if (Offset
> MaxSize
) {
79 return EFI_INVALID_PARAMETER
;
82 *Name
= (CHAR16
*) (BytePtr
+ Offset
);
83 Offset
= Offset
+ *(UINT32
*)BytePtr
;
84 if (Offset
> MaxSize
) {
85 return EFI_INVALID_PARAMETER
;
88 *Guid
= (EFI_GUID
*) (BytePtr
+ Offset
);
89 Offset
= Offset
+ sizeof (EFI_GUID
);
90 if (Offset
> MaxSize
) {
91 return EFI_INVALID_PARAMETER
;
94 *Attributes
= *(UINT32
*) (BytePtr
+ Offset
);
95 Offset
= Offset
+ sizeof (UINT32
);
96 if (Offset
> MaxSize
) {
97 return EFI_INVALID_PARAMETER
;
100 *DataSize
= *(UINT32
*) (BytePtr
+ Offset
);
101 Offset
= Offset
+ sizeof (UINT32
);
102 if (Offset
> MaxSize
) {
103 return EFI_INVALID_PARAMETER
;
106 *Data
= (VOID
*) (BytePtr
+ Offset
);
107 Offset
= Offset
+ *DataSize
;
108 if (Offset
> MaxSize
) {
109 return EFI_INVALID_PARAMETER
;
119 Iterates through the variables in the buffer, and calls a callback
120 function for each variable found.
122 @param[in] CallbackFunction - Function called for each variable instance
123 @param[in] Context - Passed to each call of CallbackFunction
124 @param[in] Buffer - Buffer containing serialized variables
125 @param[in] MaxSize - Size of Buffer in bytes
127 @return EFI_STATUS based on the success or failure of the operation
132 IterateVariablesInBuffer (
133 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
134 IN VOID
*CallbackContext
,
139 RETURN_STATUS Status
;
146 UINT32 AlignedNameMaxSize
;
154 AlignedNameMaxSize
= 0;
162 Status
= EFI_SUCCESS
, TotalSizeUsed
= 0;
163 !EFI_ERROR (Status
) && (TotalSizeUsed
< MaxSize
);
165 Status
= UnpackVariableFromBuffer (
166 (VOID
*) ((UINT8
*) Buffer
+ TotalSizeUsed
),
167 (MaxSize
- TotalSizeUsed
),
176 if (EFI_ERROR (Status
)) {
181 // We copy the name to a separately allocated buffer,
182 // to be sure it is 16-bit aligned.
184 if (NameSize
> AlignedNameMaxSize
) {
185 if (AlignedName
!= NULL
) {
186 FreePool (AlignedName
);
188 AlignedName
= AllocatePool (NameSize
);
190 if (AlignedName
== NULL
) {
191 return EFI_OUT_OF_RESOURCES
;
193 CopyMem (AlignedName
, Name
, NameSize
);
195 TotalSizeUsed
= TotalSizeUsed
+ SizeUsed
;
198 // Run the callback function
200 Status
= (*CallbackFunction
) (
211 if (AlignedName
!= NULL
) {
212 FreePool (AlignedName
);
216 // Make sure the entire buffer was used, or else return an error
218 if (TotalSizeUsed
!= MaxSize
) {
221 "Deserialize variables error: TotalSizeUsed(%Lu) != MaxSize(%Lu)\n",
222 (UINT64
)TotalSizeUsed
,
225 return EFI_INVALID_PARAMETER
;
235 IterateVariablesCallbackNop (
237 IN CHAR16
*VariableName
,
238 IN EFI_GUID
*VendorGuid
,
239 IN UINT32 Attributes
,
244 return RETURN_SUCCESS
;
251 IterateVariablesCallbackSetInInstance (
253 IN CHAR16
*VariableName
,
254 IN EFI_GUID
*VendorGuid
,
255 IN UINT32 Attributes
,
262 Instance
= (EFI_HANDLE
) Context
;
264 return SerializeVariablesAddVariable (
278 IterateVariablesCallbackSetSystemVariable (
280 IN CHAR16
*VariableName
,
281 IN EFI_GUID
*VendorGuid
,
282 IN UINT32 Attributes
,
288 STATIC CONST UINT32 AuthMask
=
289 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
|
290 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
292 Status
= gRT
->SetVariable (
300 if (Status
== EFI_SECURITY_VIOLATION
&& (Attributes
& AuthMask
) != 0) {
301 DEBUG ((DEBUG_WARN
, "%a: setting authenticated variable \"%s\" "
302 "failed with EFI_SECURITY_VIOLATION, ignoring\n", __FUNCTION__
,
304 Status
= EFI_SUCCESS
;
305 } else if (Status
== EFI_WRITE_PROTECTED
) {
306 DEBUG ((DEBUG_WARN
, "%a: setting ReadOnly variable \"%s\" "
307 "failed with EFI_WRITE_PROTECTED, ignoring\n", __FUNCTION__
,
309 Status
= EFI_SUCCESS
;
317 EnsureExtraBufferSpace (
318 IN SV_INSTANCE
*Instance
,
325 NewSize
= Instance
->DataSize
+ Size
;
326 if (NewSize
<= Instance
->BufferSize
) {
327 return RETURN_SUCCESS
;
331 // Double the required size to lessen the need to re-allocate in the future
333 NewSize
= 2 * NewSize
;
335 NewBuffer
= AllocatePool (NewSize
);
336 if (NewBuffer
== NULL
) {
337 return RETURN_OUT_OF_RESOURCES
;
340 if (Instance
->BufferPtr
!= NULL
) {
341 CopyMem (NewBuffer
, Instance
->BufferPtr
, Instance
->DataSize
);
342 FreePool (Instance
->BufferPtr
);
345 Instance
->BufferPtr
= NewBuffer
;
346 Instance
->BufferSize
= NewSize
;
348 return RETURN_SUCCESS
;
355 IN SV_INSTANCE
*Instance
,
362 ASSERT (Instance
!= NULL
);
363 ASSERT (Data
!= NULL
);
365 NewSize
= Instance
->DataSize
+ Size
;
366 ASSERT ((Instance
->DataSize
+ Size
) <= Instance
->BufferSize
);
369 (VOID
*) (((UINT8
*) (Instance
->BufferPtr
)) + Instance
->DataSize
),
374 Instance
->DataSize
= NewSize
;
379 Creates a new variable serialization instance
381 @param[out] Handle - Handle for a variable serialization instance
383 @retval RETURN_SUCCESS - The variable serialization instance was
384 successfully created.
385 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
386 create the variable serialization instance.
391 SerializeVariablesNewInstance (
392 OUT EFI_HANDLE
*Handle
397 New
= AllocateZeroPool (sizeof (*New
));
399 return RETURN_OUT_OF_RESOURCES
;
402 New
->Signature
= SV_SIGNATURE
;
404 *Handle
= (EFI_HANDLE
) New
;
405 return RETURN_SUCCESS
;
410 Free memory associated with a variable serialization instance
412 @param[in] Handle - Handle for a variable serialization instance
414 @retval RETURN_SUCCESS - The variable serialization instance was
416 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
417 variable serialization instance.
422 SerializeVariablesFreeInstance (
426 SV_INSTANCE
*Instance
;
428 Instance
= SV_FROM_HANDLE (Handle
);
430 if (Instance
->Signature
!= SV_SIGNATURE
) {
431 return RETURN_INVALID_PARAMETER
;
434 Instance
->Signature
= 0;
436 if (Instance
->BufferPtr
!= NULL
) {
437 FreePool (Instance
->BufferPtr
);
442 return RETURN_SUCCESS
;
447 Creates a new variable serialization instance using the given
448 binary representation of the variables to fill the new instance
450 @param[out] Handle - Handle for a variable serialization instance
451 @param[in] Buffer - A buffer with the serialized representation
452 of the variables. Must be the same format as produced
453 by SerializeVariablesToBuffer.
454 @param[in] Size - This is the size of the binary representation
457 @retval RETURN_SUCCESS - The binary representation was successfully
458 imported into a new variable serialization instance
459 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
460 create the new variable serialization instance
465 SerializeVariablesNewInstanceFromBuffer (
466 OUT EFI_HANDLE
*Handle
,
471 RETURN_STATUS Status
;
473 Status
= SerializeVariablesNewInstance (Handle
);
474 if (RETURN_ERROR (Status
)) {
478 Status
= IterateVariablesInBuffer (
479 IterateVariablesCallbackNop
,
484 if (RETURN_ERROR (Status
)) {
485 SerializeVariablesFreeInstance (*Handle
);
489 Status
= IterateVariablesInBuffer (
490 IterateVariablesCallbackSetInInstance
,
495 if (RETURN_ERROR (Status
)) {
496 SerializeVariablesFreeInstance (*Handle
);
505 Iterates all variables found with RuntimeServices GetNextVariableName
507 @param[in] CallbackFunction - Function called for each variable instance
508 @param[in] Context - Passed to each call of CallbackFunction
510 @retval RETURN_SUCCESS - All variables were iterated without the
511 CallbackFunction returning an error
512 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
513 iterate through the variables
514 @return Any of RETURN_ERROR indicates an error reading the variable
515 or an error was returned from CallbackFunction
520 SerializeVariablesIterateSystemVariables (
521 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
525 RETURN_STATUS Status
;
526 UINTN VariableNameBufferSize
;
527 UINTN VariableNameSize
;
528 CHAR16
*VariableName
;
530 UINTN VariableDataBufferSize
;
531 UINTN VariableDataSize
;
533 UINT32 VariableAttributes
;
537 // Initialize the variable name and data buffer variables.
539 VariableNameBufferSize
= sizeof (CHAR16
);
540 VariableName
= AllocateZeroPool (VariableNameBufferSize
);
542 VariableDataBufferSize
= 0;
547 // Get the next variable name and guid
549 VariableNameSize
= VariableNameBufferSize
;
550 Status
= gRT
->GetNextVariableName (
555 if (Status
== EFI_BUFFER_TOO_SMALL
) {
557 // The currently allocated VariableName buffer is too small,
558 // so we allocate a larger buffer, and copy the old buffer
561 NewBuffer
= AllocatePool (VariableNameSize
);
562 if (NewBuffer
== NULL
) {
563 Status
= EFI_OUT_OF_RESOURCES
;
566 CopyMem (NewBuffer
, VariableName
, VariableNameBufferSize
);
567 if (VariableName
!= NULL
) {
568 FreePool (VariableName
);
570 VariableName
= NewBuffer
;
571 VariableNameBufferSize
= VariableNameSize
;
574 // Try to get the next variable name again with the larger buffer.
576 Status
= gRT
->GetNextVariableName (
583 if (EFI_ERROR (Status
)) {
584 if (Status
== EFI_NOT_FOUND
) {
585 Status
= EFI_SUCCESS
;
591 // Get the variable data and attributes
593 VariableDataSize
= VariableDataBufferSize
;
594 Status
= gRT
->GetVariable (
601 if (Status
== EFI_BUFFER_TOO_SMALL
) {
603 // The currently allocated VariableData buffer is too small,
604 // so we allocate a larger buffer.
606 if (VariableDataBufferSize
!= 0) {
607 FreePool (VariableData
);
609 VariableDataBufferSize
= 0;
611 VariableData
= AllocatePool (VariableDataSize
);
612 if (VariableData
== NULL
) {
613 Status
= EFI_OUT_OF_RESOURCES
;
616 VariableDataBufferSize
= VariableDataSize
;
619 // Try to read the variable again with the larger buffer.
621 Status
= gRT
->GetVariable (
629 if (EFI_ERROR (Status
)) {
634 // Run the callback function
636 Status
= (*CallbackFunction
) (
644 if (EFI_ERROR (Status
)) {
650 if (VariableName
!= NULL
) {
651 FreePool (VariableName
);
654 if (VariableData
!= NULL
) {
655 FreePool (VariableData
);
663 Iterates all variables found in the variable serialization instance
665 @param[in] Handle - Handle for a variable serialization instance
666 @param[in] CallbackFunction - Function called for each variable instance
667 @param[in] Context - Passed to each call of CallbackFunction
669 @retval RETURN_SUCCESS - All variables were iterated without the
670 CallbackFunction returning an error
671 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
672 iterate through the variables
673 @return Any of RETURN_ERROR indicates an error reading the variable
674 or an error was returned from CallbackFunction
679 SerializeVariablesIterateInstanceVariables (
680 IN EFI_HANDLE Handle
,
681 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
685 SV_INSTANCE
*Instance
;
687 Instance
= SV_FROM_HANDLE (Handle
);
689 if ((Instance
->BufferPtr
!= NULL
) && (Instance
->DataSize
!= 0)) {
690 return IterateVariablesInBuffer (
697 return RETURN_SUCCESS
;
703 Sets all variables found in the variable serialization instance
705 @param[in] Handle - Handle for a variable serialization instance
707 @retval RETURN_SUCCESS - All variables were set successfully
708 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
709 set all the variables
710 @return Any of RETURN_ERROR indicates an error reading the variables
711 or in attempting to set a variable
716 SerializeVariablesSetSerializedVariables (
720 return SerializeVariablesIterateInstanceVariables (
722 IterateVariablesCallbackSetSystemVariable
,
729 Adds a variable to the variable serialization instance
731 @param[in] Handle - Handle for a variable serialization instance
732 @param[in] VariableName - Refer to RuntimeServices GetVariable
733 @param[in] VendorGuid - Refer to RuntimeServices GetVariable
734 @param[in] Attributes - Refer to RuntimeServices GetVariable
735 @param[in] DataSize - Refer to RuntimeServices GetVariable
736 @param[in] Data - Refer to RuntimeServices GetVariable
738 @retval RETURN_SUCCESS - All variables were set successfully
739 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
741 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
742 variable serialization instance or
743 VariableName, VariableGuid or Data are NULL.
748 SerializeVariablesAddVariable (
749 IN EFI_HANDLE Handle
,
750 IN CHAR16
*VariableName
,
751 IN EFI_GUID
*VendorGuid
,
752 IN UINT32 Attributes
,
757 RETURN_STATUS Status
;
758 SV_INSTANCE
*Instance
;
759 UINT32 SerializedNameSize
;
760 UINT32 SerializedDataSize
;
761 UINTN SerializedSize
;
763 Instance
= SV_FROM_HANDLE (Handle
);
765 if ((Instance
->Signature
!= SV_SIGNATURE
) ||
766 (VariableName
== NULL
) || (VendorGuid
== NULL
) || (Data
== NULL
)) {
769 SerializedNameSize
= (UINT32
) StrSize (VariableName
);
772 sizeof (SerializedNameSize
) +
774 sizeof (*VendorGuid
) +
775 sizeof (Attributes
) +
776 sizeof (SerializedDataSize
) +
779 Status
= EnsureExtraBufferSpace (
783 if (RETURN_ERROR (Status
)) {
788 // Add name size (UINT32)
790 AppendToBuffer (Instance
, (VOID
*) &SerializedNameSize
, sizeof (SerializedNameSize
));
793 // Add variable unicode name string
795 AppendToBuffer (Instance
, (VOID
*) VariableName
, SerializedNameSize
);
800 AppendToBuffer (Instance
, (VOID
*) VendorGuid
, sizeof (*VendorGuid
));
803 // Add variable attributes
805 AppendToBuffer (Instance
, (VOID
*) &Attributes
, sizeof (Attributes
));
808 // Add variable data size (UINT32)
810 SerializedDataSize
= (UINT32
) DataSize
;
811 AppendToBuffer (Instance
, (VOID
*) &SerializedDataSize
, sizeof (SerializedDataSize
));
816 AppendToBuffer (Instance
, Data
, DataSize
);
818 return RETURN_SUCCESS
;
823 Serializes the variables known to this instance into the
826 @param[in] Handle - Handle for a variable serialization instance
827 @param[out] Buffer - A buffer to store the binary representation
829 @param[in,out] Size - On input this is the size of the buffer.
830 On output this is the size of the binary representation
833 @retval RETURN_SUCCESS - The binary representation was successfully
834 completed and returned in the buffer.
835 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
836 save the variables to the buffer.
837 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
838 variable serialization instance or
839 Size or Buffer were NULL.
840 @retval RETURN_BUFFER_TOO_SMALL - The Buffer size as indicated by
841 the Size parameter was too small for the serialized
842 variable data. Size is returned with the required size.
847 SerializeVariablesToBuffer (
848 IN EFI_HANDLE Handle
,
853 SV_INSTANCE
*Instance
;
855 Instance
= SV_FROM_HANDLE (Handle
);
858 return RETURN_INVALID_PARAMETER
;
861 if (*Size
< Instance
->DataSize
) {
862 *Size
= Instance
->DataSize
;
863 return RETURN_BUFFER_TOO_SMALL
;
866 if (Buffer
== NULL
) {
867 return RETURN_INVALID_PARAMETER
;
870 *Size
= Instance
->DataSize
;
871 CopyMem (Buffer
, Instance
->BufferPtr
, Instance
->DataSize
);
873 return RETURN_SUCCESS
;