2 Serialize Variables Library implementation
4 Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "SerializeVariablesLib.h"
14 The SerializeVariablesLib interface does not specify a format
15 for the serialization of the variable data. This library uses
16 a packed array of a non-uniformly sized data structure elements.
18 Each variable is stored (packed) as:
19 UINT32 VendorNameSize; // Name size in bytes
20 CHAR16 VendorName[?]; // The variable unicode name including the
21 // null terminating character.
22 EFI_GUID VendorGuid; // The variable GUID
23 UINT32 DataSize; // The size of variable data in bytes
24 UINT8 Data[?]; // The variable data
30 Unpacks the next variable from the buffer
32 @param[in] Buffer - Buffer pointing to the next variable instance
33 On subsequent calls, the pointer should be incremented
34 by the returned SizeUsed value.
35 @param[in] MaxSize - Max allowable size for the variable data
36 On subsequent calls, this should be decremented
37 by the returned SizeUsed value.
38 @param[out] Name - Variable name string (address in Buffer)
39 @param[out] NameSize - Size of Name in bytes
40 @param[out] Guid - GUID of variable (address in Buffer)
41 @param[out] Attributes - Attributes of variable
42 @param[out] Data - Buffer containing Data for variable (address in Buffer)
43 @param[out] DataSize - Size of Data in bytes
44 @param[out] SizeUsed - Total size used for this variable instance in Buffer
46 @return EFI_STATUS based on the success or failure of the operation
51 UnpackVariableFromBuffer (
57 OUT UINT32
*Attributes
,
66 BytePtr
= (UINT8
*)Buffer
;
69 *NameSize
= *(UINT32
*) (BytePtr
+ Offset
);
70 Offset
= Offset
+ sizeof (UINT32
);
72 if (Offset
> MaxSize
) {
73 return EFI_INVALID_PARAMETER
;
76 *Name
= (CHAR16
*) (BytePtr
+ Offset
);
77 Offset
= Offset
+ *(UINT32
*)BytePtr
;
78 if (Offset
> MaxSize
) {
79 return EFI_INVALID_PARAMETER
;
82 *Guid
= (EFI_GUID
*) (BytePtr
+ Offset
);
83 Offset
= Offset
+ sizeof (EFI_GUID
);
84 if (Offset
> MaxSize
) {
85 return EFI_INVALID_PARAMETER
;
88 *Attributes
= *(UINT32
*) (BytePtr
+ Offset
);
89 Offset
= Offset
+ sizeof (UINT32
);
90 if (Offset
> MaxSize
) {
91 return EFI_INVALID_PARAMETER
;
94 *DataSize
= *(UINT32
*) (BytePtr
+ Offset
);
95 Offset
= Offset
+ sizeof (UINT32
);
96 if (Offset
> MaxSize
) {
97 return EFI_INVALID_PARAMETER
;
100 *Data
= (VOID
*) (BytePtr
+ Offset
);
101 Offset
= Offset
+ *DataSize
;
102 if (Offset
> MaxSize
) {
103 return EFI_INVALID_PARAMETER
;
113 Iterates through the variables in the buffer, and calls a callback
114 function for each variable found.
116 @param[in] CallbackFunction - Function called for each variable instance
117 @param[in] Context - Passed to each call of CallbackFunction
118 @param[in] Buffer - Buffer containing serialized variables
119 @param[in] MaxSize - Size of Buffer in bytes
121 @return EFI_STATUS based on the success or failure of the operation
126 IterateVariablesInBuffer (
127 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
128 IN VOID
*CallbackContext
,
133 RETURN_STATUS Status
;
140 UINT32 AlignedNameMaxSize
;
148 AlignedNameMaxSize
= 0;
156 Status
= EFI_SUCCESS
, TotalSizeUsed
= 0;
157 !EFI_ERROR (Status
) && (TotalSizeUsed
< MaxSize
);
159 Status
= UnpackVariableFromBuffer (
160 (VOID
*) ((UINT8
*) Buffer
+ TotalSizeUsed
),
161 (MaxSize
- TotalSizeUsed
),
170 if (EFI_ERROR (Status
)) {
175 // We copy the name to a separately allocated buffer,
176 // to be sure it is 16-bit aligned.
178 if (NameSize
> AlignedNameMaxSize
) {
179 if (AlignedName
!= NULL
) {
180 FreePool (AlignedName
);
182 AlignedName
= AllocatePool (NameSize
);
184 if (AlignedName
== NULL
) {
185 return EFI_OUT_OF_RESOURCES
;
187 CopyMem (AlignedName
, Name
, NameSize
);
189 TotalSizeUsed
= TotalSizeUsed
+ SizeUsed
;
192 // Run the callback function
194 Status
= (*CallbackFunction
) (
205 if (AlignedName
!= NULL
) {
206 FreePool (AlignedName
);
210 // Make sure the entire buffer was used, or else return an error
212 if (TotalSizeUsed
!= MaxSize
) {
215 "Deserialize variables error: TotalSizeUsed(%Lu) != MaxSize(%Lu)\n",
216 (UINT64
)TotalSizeUsed
,
219 return EFI_INVALID_PARAMETER
;
229 IterateVariablesCallbackNop (
231 IN CHAR16
*VariableName
,
232 IN EFI_GUID
*VendorGuid
,
233 IN UINT32 Attributes
,
238 return RETURN_SUCCESS
;
245 IterateVariablesCallbackSetInInstance (
247 IN CHAR16
*VariableName
,
248 IN EFI_GUID
*VendorGuid
,
249 IN UINT32 Attributes
,
256 Instance
= (EFI_HANDLE
) Context
;
258 return SerializeVariablesAddVariable (
272 IterateVariablesCallbackSetSystemVariable (
274 IN CHAR16
*VariableName
,
275 IN EFI_GUID
*VendorGuid
,
276 IN UINT32 Attributes
,
282 STATIC CONST UINT32 AuthMask
=
283 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
|
284 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
286 Status
= gRT
->SetVariable (
294 if (Status
== EFI_SECURITY_VIOLATION
&& (Attributes
& AuthMask
) != 0) {
295 DEBUG ((DEBUG_WARN
, "%a: setting authenticated variable \"%s\" "
296 "failed with EFI_SECURITY_VIOLATION, ignoring\n", __FUNCTION__
,
298 Status
= EFI_SUCCESS
;
299 } else if (Status
== EFI_WRITE_PROTECTED
) {
300 DEBUG ((DEBUG_WARN
, "%a: setting ReadOnly variable \"%s\" "
301 "failed with EFI_WRITE_PROTECTED, ignoring\n", __FUNCTION__
,
303 Status
= EFI_SUCCESS
;
311 EnsureExtraBufferSpace (
312 IN SV_INSTANCE
*Instance
,
319 NewSize
= Instance
->DataSize
+ Size
;
320 if (NewSize
<= Instance
->BufferSize
) {
321 return RETURN_SUCCESS
;
325 // Double the required size to lessen the need to re-allocate in the future
327 NewSize
= 2 * NewSize
;
329 NewBuffer
= AllocatePool (NewSize
);
330 if (NewBuffer
== NULL
) {
331 return RETURN_OUT_OF_RESOURCES
;
334 if (Instance
->BufferPtr
!= NULL
) {
335 CopyMem (NewBuffer
, Instance
->BufferPtr
, Instance
->DataSize
);
336 FreePool (Instance
->BufferPtr
);
339 Instance
->BufferPtr
= NewBuffer
;
340 Instance
->BufferSize
= NewSize
;
342 return RETURN_SUCCESS
;
349 IN SV_INSTANCE
*Instance
,
356 ASSERT (Instance
!= NULL
);
357 ASSERT (Data
!= NULL
);
359 NewSize
= Instance
->DataSize
+ Size
;
360 ASSERT ((Instance
->DataSize
+ Size
) <= Instance
->BufferSize
);
363 (VOID
*) (((UINT8
*) (Instance
->BufferPtr
)) + Instance
->DataSize
),
368 Instance
->DataSize
= NewSize
;
373 Creates a new variable serialization instance
375 @param[out] Handle - Handle for a variable serialization instance
377 @retval RETURN_SUCCESS - The variable serialization instance was
378 successfully created.
379 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
380 create the variable serialization instance.
385 SerializeVariablesNewInstance (
386 OUT EFI_HANDLE
*Handle
391 New
= AllocateZeroPool (sizeof (*New
));
393 return RETURN_OUT_OF_RESOURCES
;
396 New
->Signature
= SV_SIGNATURE
;
398 *Handle
= (EFI_HANDLE
) New
;
399 return RETURN_SUCCESS
;
404 Free memory associated with a variable serialization instance
406 @param[in] Handle - Handle for a variable serialization instance
408 @retval RETURN_SUCCESS - The variable serialization instance was
410 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
411 variable serialization instance.
416 SerializeVariablesFreeInstance (
420 SV_INSTANCE
*Instance
;
422 Instance
= SV_FROM_HANDLE (Handle
);
424 if (Instance
->Signature
!= SV_SIGNATURE
) {
425 return RETURN_INVALID_PARAMETER
;
428 Instance
->Signature
= 0;
430 if (Instance
->BufferPtr
!= NULL
) {
431 FreePool (Instance
->BufferPtr
);
436 return RETURN_SUCCESS
;
441 Creates a new variable serialization instance using the given
442 binary representation of the variables to fill the new instance
444 @param[out] Handle - Handle for a variable serialization instance
445 @param[in] Buffer - A buffer with the serialized representation
446 of the variables. Must be the same format as produced
447 by SerializeVariablesToBuffer.
448 @param[in] Size - This is the size of the binary representation
451 @retval RETURN_SUCCESS - The binary representation was successfully
452 imported into a new variable serialization instance
453 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
454 create the new variable serialization instance
459 SerializeVariablesNewInstanceFromBuffer (
460 OUT EFI_HANDLE
*Handle
,
465 RETURN_STATUS Status
;
467 Status
= SerializeVariablesNewInstance (Handle
);
468 if (RETURN_ERROR (Status
)) {
472 Status
= IterateVariablesInBuffer (
473 IterateVariablesCallbackNop
,
478 if (RETURN_ERROR (Status
)) {
479 SerializeVariablesFreeInstance (*Handle
);
483 Status
= IterateVariablesInBuffer (
484 IterateVariablesCallbackSetInInstance
,
489 if (RETURN_ERROR (Status
)) {
490 SerializeVariablesFreeInstance (*Handle
);
499 Iterates all variables found with RuntimeServices GetNextVariableName
501 @param[in] CallbackFunction - Function called for each variable instance
502 @param[in] Context - Passed to each call of CallbackFunction
504 @retval RETURN_SUCCESS - All variables were iterated without the
505 CallbackFunction returning an error
506 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
507 iterate through the variables
508 @return Any of RETURN_ERROR indicates an error reading the variable
509 or an error was returned from CallbackFunction
514 SerializeVariablesIterateSystemVariables (
515 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
519 RETURN_STATUS Status
;
520 UINTN VariableNameBufferSize
;
521 UINTN VariableNameSize
;
522 CHAR16
*VariableName
;
524 UINTN VariableDataBufferSize
;
525 UINTN VariableDataSize
;
527 UINT32 VariableAttributes
;
531 // Initialize the variable name and data buffer variables.
533 VariableNameBufferSize
= sizeof (CHAR16
);
534 VariableName
= AllocateZeroPool (VariableNameBufferSize
);
536 VariableDataBufferSize
= 0;
541 // Get the next variable name and guid
543 VariableNameSize
= VariableNameBufferSize
;
544 Status
= gRT
->GetNextVariableName (
549 if (Status
== EFI_BUFFER_TOO_SMALL
) {
551 // The currently allocated VariableName buffer is too small,
552 // so we allocate a larger buffer, and copy the old buffer
555 NewBuffer
= AllocatePool (VariableNameSize
);
556 if (NewBuffer
== NULL
) {
557 Status
= EFI_OUT_OF_RESOURCES
;
560 CopyMem (NewBuffer
, VariableName
, VariableNameBufferSize
);
561 if (VariableName
!= NULL
) {
562 FreePool (VariableName
);
564 VariableName
= NewBuffer
;
565 VariableNameBufferSize
= VariableNameSize
;
568 // Try to get the next variable name again with the larger buffer.
570 Status
= gRT
->GetNextVariableName (
577 if (EFI_ERROR (Status
)) {
578 if (Status
== EFI_NOT_FOUND
) {
579 Status
= EFI_SUCCESS
;
585 // Get the variable data and attributes
587 VariableDataSize
= VariableDataBufferSize
;
588 Status
= gRT
->GetVariable (
595 if (Status
== EFI_BUFFER_TOO_SMALL
) {
597 // The currently allocated VariableData buffer is too small,
598 // so we allocate a larger buffer.
600 if (VariableDataBufferSize
!= 0) {
601 FreePool (VariableData
);
603 VariableDataBufferSize
= 0;
605 VariableData
= AllocatePool (VariableDataSize
);
606 if (VariableData
== NULL
) {
607 Status
= EFI_OUT_OF_RESOURCES
;
610 VariableDataBufferSize
= VariableDataSize
;
613 // Try to read the variable again with the larger buffer.
615 Status
= gRT
->GetVariable (
623 if (EFI_ERROR (Status
)) {
628 // Run the callback function
630 Status
= (*CallbackFunction
) (
638 if (EFI_ERROR (Status
)) {
644 if (VariableName
!= NULL
) {
645 FreePool (VariableName
);
648 if (VariableData
!= NULL
) {
649 FreePool (VariableData
);
657 Iterates all variables found in the variable serialization instance
659 @param[in] Handle - Handle for a variable serialization instance
660 @param[in] CallbackFunction - Function called for each variable instance
661 @param[in] Context - Passed to each call of CallbackFunction
663 @retval RETURN_SUCCESS - All variables were iterated without the
664 CallbackFunction returning an error
665 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
666 iterate through the variables
667 @return Any of RETURN_ERROR indicates an error reading the variable
668 or an error was returned from CallbackFunction
673 SerializeVariablesIterateInstanceVariables (
674 IN EFI_HANDLE Handle
,
675 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
679 SV_INSTANCE
*Instance
;
681 Instance
= SV_FROM_HANDLE (Handle
);
683 if ((Instance
->BufferPtr
!= NULL
) && (Instance
->DataSize
!= 0)) {
684 return IterateVariablesInBuffer (
691 return RETURN_SUCCESS
;
697 Sets all variables found in the variable serialization instance
699 @param[in] Handle - Handle for a variable serialization instance
701 @retval RETURN_SUCCESS - All variables were set successfully
702 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
703 set all the variables
704 @return Any of RETURN_ERROR indicates an error reading the variables
705 or in attempting to set a variable
710 SerializeVariablesSetSerializedVariables (
714 return SerializeVariablesIterateInstanceVariables (
716 IterateVariablesCallbackSetSystemVariable
,
723 Adds a variable to the variable serialization instance
725 @param[in] Handle - Handle for a variable serialization instance
726 @param[in] VariableName - Refer to RuntimeServices GetVariable
727 @param[in] VendorGuid - Refer to RuntimeServices GetVariable
728 @param[in] Attributes - Refer to RuntimeServices GetVariable
729 @param[in] DataSize - Refer to RuntimeServices GetVariable
730 @param[in] Data - Refer to RuntimeServices GetVariable
732 @retval RETURN_SUCCESS - All variables were set successfully
733 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
735 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
736 variable serialization instance or
737 VariableName, VariableGuid or Data are NULL.
742 SerializeVariablesAddVariable (
743 IN EFI_HANDLE Handle
,
744 IN CHAR16
*VariableName
,
745 IN EFI_GUID
*VendorGuid
,
746 IN UINT32 Attributes
,
751 RETURN_STATUS Status
;
752 SV_INSTANCE
*Instance
;
753 UINT32 SerializedNameSize
;
754 UINT32 SerializedDataSize
;
755 UINTN SerializedSize
;
757 Instance
= SV_FROM_HANDLE (Handle
);
759 if ((Instance
->Signature
!= SV_SIGNATURE
) ||
760 (VariableName
== NULL
) || (VendorGuid
== NULL
) || (Data
== NULL
)) {
763 SerializedNameSize
= (UINT32
) StrSize (VariableName
);
766 sizeof (SerializedNameSize
) +
768 sizeof (*VendorGuid
) +
769 sizeof (Attributes
) +
770 sizeof (SerializedDataSize
) +
773 Status
= EnsureExtraBufferSpace (
777 if (RETURN_ERROR (Status
)) {
782 // Add name size (UINT32)
784 AppendToBuffer (Instance
, (VOID
*) &SerializedNameSize
, sizeof (SerializedNameSize
));
787 // Add variable unicode name string
789 AppendToBuffer (Instance
, (VOID
*) VariableName
, SerializedNameSize
);
794 AppendToBuffer (Instance
, (VOID
*) VendorGuid
, sizeof (*VendorGuid
));
797 // Add variable attributes
799 AppendToBuffer (Instance
, (VOID
*) &Attributes
, sizeof (Attributes
));
802 // Add variable data size (UINT32)
804 SerializedDataSize
= (UINT32
) DataSize
;
805 AppendToBuffer (Instance
, (VOID
*) &SerializedDataSize
, sizeof (SerializedDataSize
));
810 AppendToBuffer (Instance
, Data
, DataSize
);
812 return RETURN_SUCCESS
;
817 Serializes the variables known to this instance into the
820 @param[in] Handle - Handle for a variable serialization instance
821 @param[out] Buffer - A buffer to store the binary representation
823 @param[in,out] Size - On input this is the size of the buffer.
824 On output this is the size of the binary representation
827 @retval RETURN_SUCCESS - The binary representation was successfully
828 completed and returned in the buffer.
829 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
830 save the variables to the buffer.
831 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
832 variable serialization instance or
833 Size or Buffer were NULL.
834 @retval RETURN_BUFFER_TOO_SMALL - The Buffer size as indicated by
835 the Size parameter was too small for the serialized
836 variable data. Size is returned with the required size.
841 SerializeVariablesToBuffer (
842 IN EFI_HANDLE Handle
,
847 SV_INSTANCE
*Instance
;
849 Instance
= SV_FROM_HANDLE (Handle
);
852 return RETURN_INVALID_PARAMETER
;
855 if (*Size
< Instance
->DataSize
) {
856 *Size
= Instance
->DataSize
;
857 return RETURN_BUFFER_TOO_SMALL
;
860 if (Buffer
== NULL
) {
861 return RETURN_INVALID_PARAMETER
;
864 *Size
= Instance
->DataSize
;
865 CopyMem (Buffer
, Instance
->BufferPtr
, Instance
->DataSize
);
867 return RETURN_SUCCESS
;