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(%d) != MaxSize(%d)\n",
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
,
287 return gRT
->SetVariable (
299 EnsureExtraBufferSpace (
300 IN SV_INSTANCE
*Instance
,
307 NewSize
= Instance
->DataSize
+ Size
;
308 if (NewSize
<= Instance
->BufferSize
) {
309 return RETURN_SUCCESS
;
313 // Double the required size to lessen the need to re-allocate in the future
315 NewSize
= 2 * NewSize
;
317 NewBuffer
= AllocatePool (NewSize
);
318 if (NewBuffer
== NULL
) {
319 return RETURN_OUT_OF_RESOURCES
;
322 if (Instance
->BufferPtr
!= NULL
) {
323 CopyMem (NewBuffer
, Instance
->BufferPtr
, Instance
->DataSize
);
324 FreePool (Instance
->BufferPtr
);
327 Instance
->BufferPtr
= NewBuffer
;
328 Instance
->BufferSize
= NewSize
;
330 return RETURN_SUCCESS
;
337 IN SV_INSTANCE
*Instance
,
344 ASSERT (Instance
!= NULL
);
345 ASSERT (Data
!= NULL
);
347 NewSize
= Instance
->DataSize
+ Size
;
348 ASSERT ((Instance
->DataSize
+ Size
) <= Instance
->BufferSize
);
351 (VOID
*) (((UINT8
*) (Instance
->BufferPtr
)) + Instance
->DataSize
),
356 Instance
->DataSize
= NewSize
;
361 Creates a new variable serialization instance
363 @param[out] Handle - Handle for a variable serialization instance
365 @retval RETURN_SUCCESS - The variable serialization instance was
366 successfully created.
367 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
368 create the variable serialization instance.
373 SerializeVariablesNewInstance (
374 OUT EFI_HANDLE
*Handle
379 New
= AllocateZeroPool (sizeof (*New
));
381 return RETURN_OUT_OF_RESOURCES
;
384 New
->Signature
= SV_SIGNATURE
;
386 *Handle
= (EFI_HANDLE
) New
;
387 return RETURN_SUCCESS
;
392 Free memory associated with a variable serialization instance
394 @param[in] Handle - Handle for a variable serialization instance
396 @retval RETURN_SUCCESS - The variable serialization instance was
398 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
399 variable serialization instance.
404 SerializeVariablesFreeInstance (
408 SV_INSTANCE
*Instance
;
410 Instance
= SV_FROM_HANDLE (Handle
);
412 if (Instance
->Signature
!= SV_SIGNATURE
) {
413 return RETURN_INVALID_PARAMETER
;
416 Instance
->Signature
= 0;
418 if (Instance
->BufferPtr
!= NULL
) {
419 FreePool (Instance
->BufferPtr
);
424 return RETURN_SUCCESS
;
429 Creates a new variable serialization instance using the given
430 binary representation of the variables to fill the new instance
432 @param[out] Handle - Handle for a variable serialization instance
433 @param[in] Buffer - A buffer with the serialized representation
434 of the variables. Must be the same format as produced
435 by SerializeVariablesToBuffer.
436 @param[in] Size - This is the size of the binary representation
439 @retval RETURN_SUCCESS - The binary representation was successfully
440 imported into a new variable serialization instance
441 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
442 create the new variable serialization instance
447 SerializeVariablesNewInstanceFromBuffer (
448 OUT EFI_HANDLE
*Handle
,
453 RETURN_STATUS Status
;
455 Status
= SerializeVariablesNewInstance (Handle
);
456 if (RETURN_ERROR (Status
)) {
460 Status
= IterateVariablesInBuffer (
461 IterateVariablesCallbackNop
,
466 if (RETURN_ERROR (Status
)) {
467 SerializeVariablesFreeInstance (*Handle
);
471 Status
= IterateVariablesInBuffer (
472 IterateVariablesCallbackSetInInstance
,
477 if (RETURN_ERROR (Status
)) {
478 SerializeVariablesFreeInstance (*Handle
);
487 Iterates all variables found with RuntimeServices GetNextVariableName
489 @param[in] CallbackFunction - Function called for each variable instance
490 @param[in] Context - Passed to each call of CallbackFunction
492 @retval RETURN_SUCCESS - All variables were iterated without the
493 CallbackFunction returning an error
494 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
495 iterate through the variables
496 @return Any of RETURN_ERROR indicates an error reading the variable
497 or an error was returned from CallbackFunction
502 SerializeVariablesIterateSystemVariables (
503 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
507 RETURN_STATUS Status
;
508 UINTN VariableNameBufferSize
;
509 UINTN VariableNameSize
;
510 CHAR16
*VariableName
;
512 UINTN VariableDataBufferSize
;
513 UINTN VariableDataSize
;
515 UINT32 VariableAttributes
;
519 // Initialize the variable name and data buffer variables.
521 VariableNameBufferSize
= sizeof (CHAR16
);
522 VariableName
= AllocateZeroPool (VariableNameBufferSize
);
524 VariableDataBufferSize
= 0;
529 // Get the next variable name and guid
531 VariableNameSize
= VariableNameBufferSize
;
532 Status
= gRT
->GetNextVariableName (
537 if (Status
== EFI_BUFFER_TOO_SMALL
) {
539 // The currently allocated VariableName buffer is too small,
540 // so we allocate a larger buffer, and copy the old buffer
543 NewBuffer
= AllocatePool (VariableNameSize
);
544 if (NewBuffer
== NULL
) {
545 Status
= EFI_OUT_OF_RESOURCES
;
548 CopyMem (NewBuffer
, VariableName
, VariableNameBufferSize
);
549 if (VariableName
!= NULL
) {
550 FreePool (VariableName
);
552 VariableName
= NewBuffer
;
553 VariableNameBufferSize
= VariableNameSize
;
556 // Try to get the next variable name again with the larger buffer.
558 Status
= gRT
->GetNextVariableName (
565 if (EFI_ERROR (Status
)) {
566 if (Status
== EFI_NOT_FOUND
) {
567 Status
= EFI_SUCCESS
;
573 // Get the variable data and attributes
575 VariableDataSize
= VariableDataBufferSize
;
576 Status
= gRT
->GetVariable (
583 if (Status
== EFI_BUFFER_TOO_SMALL
) {
585 // The currently allocated VariableData buffer is too small,
586 // so we allocate a larger buffer.
588 if (VariableDataBufferSize
!= 0) {
589 FreePool (VariableData
);
591 VariableDataBufferSize
= 0;
593 VariableData
= AllocatePool (VariableDataSize
);
594 if (VariableData
== NULL
) {
595 Status
= EFI_OUT_OF_RESOURCES
;
598 VariableDataBufferSize
= VariableDataSize
;
601 // Try to read the variable again with the larger buffer.
603 Status
= gRT
->GetVariable (
611 if (EFI_ERROR (Status
)) {
616 // Run the callback function
618 Status
= (*CallbackFunction
) (
626 if (EFI_ERROR (Status
)) {
632 if (VariableName
!= NULL
) {
633 FreePool (VariableName
);
636 if (VariableData
!= NULL
) {
637 FreePool (VariableData
);
645 Iterates all variables found in the variable serialization instance
647 @param[in] Handle - Handle for a variable serialization instance
648 @param[in] CallbackFunction - Function called for each variable instance
649 @param[in] Context - Passed to each call of CallbackFunction
651 @retval RETURN_SUCCESS - All variables were iterated without the
652 CallbackFunction returning an error
653 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
654 iterate through the variables
655 @return Any of RETURN_ERROR indicates an error reading the variable
656 or an error was returned from CallbackFunction
661 SerializeVariablesIterateInstanceVariables (
662 IN EFI_HANDLE Handle
,
663 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
667 SV_INSTANCE
*Instance
;
669 Instance
= SV_FROM_HANDLE (Handle
);
671 if ((Instance
->BufferPtr
!= NULL
) && (Instance
->DataSize
!= 0)) {
672 return IterateVariablesInBuffer (
679 return RETURN_SUCCESS
;
685 Sets all variables found in the variable serialization instance
687 @param[in] Handle - Handle for a variable serialization instance
689 @retval RETURN_SUCCESS - All variables were set successfully
690 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
691 set all the variables
692 @return Any of RETURN_ERROR indicates an error reading the variables
693 or in attempting to set a variable
698 SerializeVariablesSetSerializedVariables (
702 return SerializeVariablesIterateInstanceVariables (
704 IterateVariablesCallbackSetSystemVariable
,
711 Adds a variable to the variable serialization instance
713 @param[in] Handle - Handle for a variable serialization instance
714 @param[in] VariableName - Refer to RuntimeServices GetVariable
715 @param[in] VendorGuid - Refer to RuntimeServices GetVariable
716 @param[in] Attributes - Refer to RuntimeServices GetVariable
717 @param[in] DataSize - Refer to RuntimeServices GetVariable
718 @param[in] Data - Refer to RuntimeServices GetVariable
720 @retval RETURN_SUCCESS - All variables were set successfully
721 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
723 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
724 variable serialization instance or
725 VariableName, VariableGuid or Data are NULL.
730 SerializeVariablesAddVariable (
731 IN EFI_HANDLE Handle
,
732 IN CHAR16
*VariableName
,
733 IN EFI_GUID
*VendorGuid
,
734 IN UINT32 Attributes
,
739 RETURN_STATUS Status
;
740 SV_INSTANCE
*Instance
;
741 UINT32 SerializedNameSize
;
742 UINT32 SerializedDataSize
;
743 UINTN SerializedSize
;
745 Instance
= SV_FROM_HANDLE (Handle
);
747 if ((Instance
->Signature
!= SV_SIGNATURE
) ||
748 (VariableName
== NULL
) || (VendorGuid
== NULL
) || (Data
== NULL
)) {
751 SerializedNameSize
= (UINT32
) StrSize (VariableName
);
754 sizeof (SerializedNameSize
) +
756 sizeof (*VendorGuid
) +
757 sizeof (Attributes
) +
758 sizeof (SerializedDataSize
) +
761 Status
= EnsureExtraBufferSpace (
765 if (RETURN_ERROR (Status
)) {
770 // Add name size (UINT32)
772 AppendToBuffer (Instance
, (VOID
*) &SerializedNameSize
, sizeof (SerializedNameSize
));
775 // Add variable unicode name string
777 AppendToBuffer (Instance
, (VOID
*) VariableName
, SerializedNameSize
);
782 AppendToBuffer (Instance
, (VOID
*) VendorGuid
, sizeof (*VendorGuid
));
785 // Add variable attributes
787 AppendToBuffer (Instance
, (VOID
*) &Attributes
, sizeof (Attributes
));
790 // Add variable data size (UINT32)
792 SerializedDataSize
= (UINT32
) DataSize
;
793 AppendToBuffer (Instance
, (VOID
*) &SerializedDataSize
, sizeof (SerializedDataSize
));
798 AppendToBuffer (Instance
, Data
, DataSize
);
800 return RETURN_SUCCESS
;
805 Serializes the variables known to this instance into the
808 @param[in] Handle - Handle for a variable serialization instance
809 @param[out] Buffer - A buffer to store the binary representation
811 @param[in,out] Size - On input this is the size of the buffer.
812 On output this is the size of the binary representation
815 @retval RETURN_SUCCESS - The binary representation was successfully
816 completed and returned in the buffer.
817 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
818 save the variables to the buffer.
819 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
820 variable serialization instance or
821 Size or Buffer were NULL.
822 @retval RETURN_BUFFER_TOO_SMALL - The Buffer size as indicated by
823 the Size parameter was too small for the serialized
824 variable data. Size is returned with the required size.
829 SerializeVariablesToBuffer (
830 IN EFI_HANDLE Handle
,
835 SV_INSTANCE
*Instance
;
837 Instance
= SV_FROM_HANDLE (Handle
);
840 return RETURN_INVALID_PARAMETER
;
843 if (*Size
< Instance
->DataSize
) {
844 *Size
= Instance
->DataSize
;
845 return RETURN_BUFFER_TOO_SMALL
;
848 if (Buffer
== NULL
) {
849 return RETURN_INVALID_PARAMETER
;
852 *Size
= Instance
->DataSize
;
853 CopyMem (Buffer
, Instance
->BufferPtr
, Instance
->DataSize
);
855 return RETURN_SUCCESS
;