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
29 Unpacks the next variable from the buffer
31 @param[in] Buffer - Buffer pointing to the next variable instance
32 On subsequent calls, the pointer should be incremented
33 by the returned SizeUsed value.
34 @param[in] MaxSize - Max allowable size for the variable data
35 On subsequent calls, this should be decremented
36 by the returned SizeUsed value.
37 @param[out] Name - Variable name string (address in Buffer)
38 @param[out] NameSize - Size of Name in bytes
39 @param[out] Guid - GUID of variable (address in Buffer)
40 @param[out] Attributes - Attributes of variable
41 @param[out] Data - Buffer containing Data for variable (address in Buffer)
42 @param[out] DataSize - Size of Data in bytes
43 @param[out] SizeUsed - Total size used for this variable instance in Buffer
45 @return EFI_STATUS based on the success or failure of the operation
50 UnpackVariableFromBuffer (
56 OUT UINT32
*Attributes
,
65 BytePtr
= (UINT8
*)Buffer
;
68 *NameSize
= *(UINT32
*)(BytePtr
+ Offset
);
69 Offset
= Offset
+ sizeof (UINT32
);
71 if (Offset
> MaxSize
) {
72 return EFI_INVALID_PARAMETER
;
75 *Name
= (CHAR16
*)(BytePtr
+ Offset
);
76 Offset
= Offset
+ *(UINT32
*)BytePtr
;
77 if (Offset
> MaxSize
) {
78 return EFI_INVALID_PARAMETER
;
81 *Guid
= (EFI_GUID
*)(BytePtr
+ Offset
);
82 Offset
= Offset
+ sizeof (EFI_GUID
);
83 if (Offset
> MaxSize
) {
84 return EFI_INVALID_PARAMETER
;
87 *Attributes
= *(UINT32
*)(BytePtr
+ Offset
);
88 Offset
= Offset
+ sizeof (UINT32
);
89 if (Offset
> MaxSize
) {
90 return EFI_INVALID_PARAMETER
;
93 *DataSize
= *(UINT32
*)(BytePtr
+ Offset
);
94 Offset
= Offset
+ sizeof (UINT32
);
95 if (Offset
> MaxSize
) {
96 return EFI_INVALID_PARAMETER
;
99 *Data
= (VOID
*)(BytePtr
+ Offset
);
100 Offset
= Offset
+ *DataSize
;
101 if (Offset
> MaxSize
) {
102 return EFI_INVALID_PARAMETER
;
111 Iterates through the variables in the buffer, and calls a callback
112 function for each variable found.
114 @param[in] CallbackFunction - Function called for each variable instance
115 @param[in] Context - Passed to each call of CallbackFunction
116 @param[in] Buffer - Buffer containing serialized variables
117 @param[in] MaxSize - Size of Buffer in bytes
119 @return EFI_STATUS based on the success or failure of the operation
124 IterateVariablesInBuffer (
125 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
126 IN VOID
*CallbackContext
,
131 RETURN_STATUS Status
;
138 UINT32 AlignedNameMaxSize
;
146 AlignedNameMaxSize
= 0;
154 Status
= EFI_SUCCESS
, TotalSizeUsed
= 0;
155 !EFI_ERROR (Status
) && (TotalSizeUsed
< MaxSize
);
158 Status
= UnpackVariableFromBuffer (
159 (VOID
*)((UINT8
*)Buffer
+ TotalSizeUsed
),
160 (MaxSize
- TotalSizeUsed
),
169 if (EFI_ERROR (Status
)) {
174 // We copy the name to a separately allocated buffer,
175 // to be sure it is 16-bit aligned.
177 if (NameSize
> AlignedNameMaxSize
) {
178 if (AlignedName
!= NULL
) {
179 FreePool (AlignedName
);
182 AlignedName
= AllocatePool (NameSize
);
185 if (AlignedName
== NULL
) {
186 return EFI_OUT_OF_RESOURCES
;
189 CopyMem (AlignedName
, Name
, NameSize
);
191 TotalSizeUsed
= TotalSizeUsed
+ SizeUsed
;
194 // Run the callback function
196 Status
= (*CallbackFunction
)(
206 if (AlignedName
!= NULL
) {
207 FreePool (AlignedName
);
211 // Make sure the entire buffer was used, or else return an error
213 if (TotalSizeUsed
!= MaxSize
) {
216 "Deserialize variables error: TotalSizeUsed(%Lu) != MaxSize(%Lu)\n",
217 (UINT64
)TotalSizeUsed
,
220 return EFI_INVALID_PARAMETER
;
229 IterateVariablesCallbackNop (
231 IN CHAR16
*VariableName
,
232 IN EFI_GUID
*VendorGuid
,
233 IN UINT32 Attributes
,
238 return RETURN_SUCCESS
;
244 IterateVariablesCallbackSetInInstance (
246 IN CHAR16
*VariableName
,
247 IN EFI_GUID
*VendorGuid
,
248 IN UINT32 Attributes
,
255 Instance
= (EFI_HANDLE
)Context
;
257 return SerializeVariablesAddVariable (
270 IterateVariablesCallbackSetSystemVariable (
272 IN CHAR16
*VariableName
,
273 IN EFI_GUID
*VendorGuid
,
274 IN UINT32 Attributes
,
280 STATIC CONST UINT32 AuthMask
=
281 EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
|
282 EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS
;
284 Status
= gRT
->SetVariable (
292 if ((Status
== EFI_SECURITY_VIOLATION
) && ((Attributes
& AuthMask
) != 0)) {
295 "%a: setting authenticated variable \"%s\" "
296 "failed with EFI_SECURITY_VIOLATION, ignoring\n",
300 Status
= EFI_SUCCESS
;
301 } else if (Status
== EFI_WRITE_PROTECTED
) {
304 "%a: setting ReadOnly variable \"%s\" "
305 "failed with EFI_WRITE_PROTECTED, ignoring\n",
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
;
354 IN SV_INSTANCE
*Instance
,
361 ASSERT (Instance
!= NULL
);
362 ASSERT (Data
!= NULL
);
364 NewSize
= Instance
->DataSize
+ Size
;
365 ASSERT ((Instance
->DataSize
+ Size
) <= Instance
->BufferSize
);
368 (VOID
*)(((UINT8
*)(Instance
->BufferPtr
)) + Instance
->DataSize
),
373 Instance
->DataSize
= NewSize
;
377 Creates a new variable serialization instance
379 @param[out] Handle - Handle for a variable serialization instance
381 @retval RETURN_SUCCESS - The variable serialization instance was
382 successfully created.
383 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
384 create the variable serialization instance.
389 SerializeVariablesNewInstance (
390 OUT EFI_HANDLE
*Handle
395 New
= AllocateZeroPool (sizeof (*New
));
397 return RETURN_OUT_OF_RESOURCES
;
400 New
->Signature
= SV_SIGNATURE
;
402 *Handle
= (EFI_HANDLE
)New
;
403 return RETURN_SUCCESS
;
407 Free memory associated with a variable serialization instance
409 @param[in] Handle - Handle for a variable serialization instance
411 @retval RETURN_SUCCESS - The variable serialization instance was
413 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
414 variable serialization instance.
419 SerializeVariablesFreeInstance (
423 SV_INSTANCE
*Instance
;
425 Instance
= SV_FROM_HANDLE (Handle
);
427 if (Instance
->Signature
!= SV_SIGNATURE
) {
428 return RETURN_INVALID_PARAMETER
;
431 Instance
->Signature
= 0;
433 if (Instance
->BufferPtr
!= NULL
) {
434 FreePool (Instance
->BufferPtr
);
439 return RETURN_SUCCESS
;
443 Creates a new variable serialization instance using the given
444 binary representation of the variables to fill the new instance
446 @param[out] Handle - Handle for a variable serialization instance
447 @param[in] Buffer - A buffer with the serialized representation
448 of the variables. Must be the same format as produced
449 by SerializeVariablesToBuffer.
450 @param[in] Size - This is the size of the binary representation
453 @retval RETURN_SUCCESS - The binary representation was successfully
454 imported into a new variable serialization instance
455 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
456 create the new variable serialization instance
461 SerializeVariablesNewInstanceFromBuffer (
462 OUT EFI_HANDLE
*Handle
,
467 RETURN_STATUS Status
;
469 Status
= SerializeVariablesNewInstance (Handle
);
470 if (RETURN_ERROR (Status
)) {
474 Status
= IterateVariablesInBuffer (
475 IterateVariablesCallbackNop
,
480 if (RETURN_ERROR (Status
)) {
481 SerializeVariablesFreeInstance (*Handle
);
485 Status
= IterateVariablesInBuffer (
486 IterateVariablesCallbackSetInInstance
,
491 if (RETURN_ERROR (Status
)) {
492 SerializeVariablesFreeInstance (*Handle
);
500 Iterates all variables found with RuntimeServices GetNextVariableName
502 @param[in] CallbackFunction - Function called for each variable instance
503 @param[in] Context - Passed to each call of CallbackFunction
505 @retval RETURN_SUCCESS - All variables were iterated without the
506 CallbackFunction returning an error
507 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
508 iterate through the variables
509 @return Any of RETURN_ERROR indicates an error reading the variable
510 or an error was returned from CallbackFunction
515 SerializeVariablesIterateSystemVariables (
516 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
520 RETURN_STATUS Status
;
521 UINTN VariableNameBufferSize
;
522 UINTN VariableNameSize
;
523 CHAR16
*VariableName
;
525 UINTN VariableDataBufferSize
;
526 UINTN VariableDataSize
;
528 UINT32 VariableAttributes
;
532 // Initialize the variable name and data buffer variables.
534 VariableNameBufferSize
= sizeof (CHAR16
);
535 VariableName
= AllocateZeroPool (VariableNameBufferSize
);
537 VariableDataBufferSize
= 0;
542 // Get the next variable name and guid
544 VariableNameSize
= VariableNameBufferSize
;
545 Status
= gRT
->GetNextVariableName (
550 if (Status
== EFI_BUFFER_TOO_SMALL
) {
552 // The currently allocated VariableName buffer is too small,
553 // so we allocate a larger buffer, and copy the old buffer
556 NewBuffer
= AllocatePool (VariableNameSize
);
557 if (NewBuffer
== NULL
) {
558 Status
= EFI_OUT_OF_RESOURCES
;
562 CopyMem (NewBuffer
, VariableName
, VariableNameBufferSize
);
563 if (VariableName
!= NULL
) {
564 FreePool (VariableName
);
567 VariableName
= NewBuffer
;
568 VariableNameBufferSize
= VariableNameSize
;
571 // Try to get the next variable name again with the larger buffer.
573 Status
= gRT
->GetNextVariableName (
580 if (EFI_ERROR (Status
)) {
581 if (Status
== EFI_NOT_FOUND
) {
582 Status
= EFI_SUCCESS
;
589 // Get the variable data and attributes
591 VariableDataSize
= VariableDataBufferSize
;
592 Status
= gRT
->GetVariable (
599 if (Status
== EFI_BUFFER_TOO_SMALL
) {
601 // The currently allocated VariableData buffer is too small,
602 // so we allocate a larger buffer.
604 if (VariableDataBufferSize
!= 0) {
605 FreePool (VariableData
);
607 VariableDataBufferSize
= 0;
610 VariableData
= AllocatePool (VariableDataSize
);
611 if (VariableData
== NULL
) {
612 Status
= EFI_OUT_OF_RESOURCES
;
616 VariableDataBufferSize
= VariableDataSize
;
619 // Try to read the variable again with the larger buffer.
621 Status
= gRT
->GetVariable (
630 if (EFI_ERROR (Status
)) {
635 // Run the callback function
637 Status
= (*CallbackFunction
)(
645 if (EFI_ERROR (Status
)) {
650 if (VariableName
!= NULL
) {
651 FreePool (VariableName
);
654 if (VariableData
!= NULL
) {
655 FreePool (VariableData
);
662 Iterates all variables found in the variable serialization instance
664 @param[in] Handle - Handle for a variable serialization instance
665 @param[in] CallbackFunction - Function called for each variable instance
666 @param[in] Context - Passed to each call of CallbackFunction
668 @retval RETURN_SUCCESS - All variables were iterated without the
669 CallbackFunction returning an error
670 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
671 iterate through the variables
672 @return Any of RETURN_ERROR indicates an error reading the variable
673 or an error was returned from CallbackFunction
678 SerializeVariablesIterateInstanceVariables (
679 IN EFI_HANDLE Handle
,
680 IN VARIABLE_SERIALIZATION_ITERATION_CALLBACK CallbackFunction
,
684 SV_INSTANCE
*Instance
;
686 Instance
= SV_FROM_HANDLE (Handle
);
688 if ((Instance
->BufferPtr
!= NULL
) && (Instance
->DataSize
!= 0)) {
689 return IterateVariablesInBuffer (
696 return RETURN_SUCCESS
;
701 Sets all variables found in the variable serialization instance
703 @param[in] Handle - Handle for a variable serialization instance
705 @retval RETURN_SUCCESS - All variables were set successfully
706 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
707 set all the variables
708 @return Any of RETURN_ERROR indicates an error reading the variables
709 or in attempting to set a variable
714 SerializeVariablesSetSerializedVariables (
718 return SerializeVariablesIterateInstanceVariables (
720 IterateVariablesCallbackSetSystemVariable
,
726 Adds a variable to the variable serialization instance
728 @param[in] Handle - Handle for a variable serialization instance
729 @param[in] VariableName - Refer to RuntimeServices GetVariable
730 @param[in] VendorGuid - Refer to RuntimeServices GetVariable
731 @param[in] Attributes - Refer to RuntimeServices GetVariable
732 @param[in] DataSize - Refer to RuntimeServices GetVariable
733 @param[in] Data - Refer to RuntimeServices GetVariable
735 @retval RETURN_SUCCESS - All variables were set successfully
736 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
738 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
739 variable serialization instance or
740 VariableName, VariableGuid or Data are NULL.
745 SerializeVariablesAddVariable (
746 IN EFI_HANDLE Handle
,
747 IN CHAR16
*VariableName
,
748 IN EFI_GUID
*VendorGuid
,
749 IN UINT32 Attributes
,
754 RETURN_STATUS Status
;
755 SV_INSTANCE
*Instance
;
756 UINT32 SerializedNameSize
;
757 UINT32 SerializedDataSize
;
758 UINTN SerializedSize
;
760 Instance
= SV_FROM_HANDLE (Handle
);
762 if ((Instance
->Signature
!= SV_SIGNATURE
) ||
763 (VariableName
== NULL
) || (VendorGuid
== NULL
) || (Data
== NULL
))
767 SerializedNameSize
= (UINT32
)StrSize (VariableName
);
770 sizeof (SerializedNameSize
) +
772 sizeof (*VendorGuid
) +
773 sizeof (Attributes
) +
774 sizeof (SerializedDataSize
) +
777 Status
= EnsureExtraBufferSpace (
781 if (RETURN_ERROR (Status
)) {
786 // Add name size (UINT32)
788 AppendToBuffer (Instance
, (VOID
*)&SerializedNameSize
, sizeof (SerializedNameSize
));
791 // Add variable unicode name string
793 AppendToBuffer (Instance
, (VOID
*)VariableName
, SerializedNameSize
);
798 AppendToBuffer (Instance
, (VOID
*)VendorGuid
, sizeof (*VendorGuid
));
801 // Add variable attributes
803 AppendToBuffer (Instance
, (VOID
*)&Attributes
, sizeof (Attributes
));
806 // Add variable data size (UINT32)
808 SerializedDataSize
= (UINT32
)DataSize
;
809 AppendToBuffer (Instance
, (VOID
*)&SerializedDataSize
, sizeof (SerializedDataSize
));
814 AppendToBuffer (Instance
, Data
, DataSize
);
816 return RETURN_SUCCESS
;
820 Serializes the variables known to this instance into the
823 @param[in] Handle - Handle for a variable serialization instance
824 @param[out] Buffer - A buffer to store the binary representation
826 @param[in,out] Size - On input this is the size of the buffer.
827 On output this is the size of the binary representation
830 @retval RETURN_SUCCESS - The binary representation was successfully
831 completed and returned in the buffer.
832 @retval RETURN_OUT_OF_RESOURCES - There we not enough resources to
833 save the variables to the buffer.
834 @retval RETURN_INVALID_PARAMETER - Handle was not a valid
835 variable serialization instance or
836 Size or Buffer were NULL.
837 @retval RETURN_BUFFER_TOO_SMALL - The Buffer size as indicated by
838 the Size parameter was too small for the serialized
839 variable data. Size is returned with the required size.
844 SerializeVariablesToBuffer (
845 IN EFI_HANDLE Handle
,
850 SV_INSTANCE
*Instance
;
852 Instance
= SV_FROM_HANDLE (Handle
);
855 return RETURN_INVALID_PARAMETER
;
858 if (*Size
< Instance
->DataSize
) {
859 *Size
= Instance
->DataSize
;
860 return RETURN_BUFFER_TOO_SMALL
;
863 if (Buffer
== NULL
) {
864 return RETURN_INVALID_PARAMETER
;
867 *Size
= Instance
->DataSize
;
868 CopyMem (Buffer
, Instance
->BufferPtr
, Instance
->DataSize
);
870 return RETURN_SUCCESS
;