3 Emulation Variable services operate on the runtime volatile memory.
4 The nonvolatile variable space doesn't exist.
6 Copyright (c) 2006 - 2008, Intel Corporation
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 /// Don't use module globals after the SetVirtualAddress map is signaled
22 ESAL_VARIABLE_GLOBAL
*mVariableModuleGlobal
;
24 VARIABLE_INFO_ENTRY
*gVariableInfo
= NULL
;
27 /// The size of a 3 character ISO639 language code.
29 #define ISO_639_2_ENTRY_SIZE 3
32 Update the variable region with Variable information. These are the same
33 arguments as the EFI Variable services.
35 @param[in] VariableName Name of variable
37 @param[in] VendorGuid Guid of variable
39 @param[in] Data Variable data
41 @param[in] DataSize Size of data. 0 means delete
43 @param[in] Attributes Attribues of the variable
45 @param[in] Variable The variable information which is used to keep track of variable usage.
47 @retval EFI_SUCCESS The update operation is success.
49 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
55 IN CHAR16
*VariableName
,
56 IN EFI_GUID
*VendorGuid
,
59 IN UINT32 Attributes OPTIONAL
,
60 IN VARIABLE_POINTER_TRACK
*Variable
64 Finds variable in storage blocks of volatile and non-volatile storage areas.
66 This code finds variable in storage blocks of volatile and non-volatile storage areas.
67 If VariableName is an empty string, then we just return the first
68 qualified variable without comparing VariableName and VendorGuid.
69 Otherwise, VariableName and VendorGuid are compared.
71 @param VariableName Name of the variable to be found.
72 @param VendorGuid Vendor GUID to be found.
73 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
74 including the range searched and the target position.
75 @param Global Pointer to VARIABLE_GLOBAL structure, including
76 base of volatile variable storage area, base of
77 NV variable storage area, and a lock.
79 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
81 @retval EFI_SUCCESS Variable successfully found.
82 @retval EFI_NOT_FOUND Variable not found.
87 IN CHAR16
*VariableName
,
88 IN EFI_GUID
*VendorGuid
,
89 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
90 IN VARIABLE_GLOBAL
*Global
94 Acquires lock only at boot time. Simply returns at runtime.
96 This is a temperary function which will be removed when
97 EfiAcquireLock() in UefiLib can handle the call in UEFI
98 Runtimer driver in RT phase.
99 It calls EfiAcquireLock() at boot time, and simply returns
102 @param Lock A pointer to the lock to acquire
106 AcquireLockOnlyAtBootTime (
110 if (!EfiAtRuntime ()) {
111 EfiAcquireLock (Lock
);
116 Releases lock only at boot time. Simply returns at runtime.
118 This is a temperary function which will be removed when
119 EfiReleaseLock() in UefiLib can handle the call in UEFI
120 Runtimer driver in RT phase.
121 It calls EfiReleaseLock() at boot time, and simply returns
124 @param Lock A pointer to the lock to release
128 ReleaseLockOnlyAtBootTime (
132 if (!EfiAtRuntime ()) {
133 EfiReleaseLock (Lock
);
138 Gets pointer to the variable data.
140 This function gets the pointer to the variable data according
141 to the input pointer to the variable header.
143 @param Variable Pointer to the variable header.
145 @return Pointer to variable data
150 IN VARIABLE_HEADER
*Variable
153 if (Variable
->StartId
!= VARIABLE_DATA
) {
157 // Be careful about pad size for alignment
159 return (UINT8
*) ((UINTN
) GET_VARIABLE_NAME_PTR (Variable
) + Variable
->NameSize
+ GET_PAD_SIZE (Variable
->NameSize
));
163 Gets pointer to header of the next variable.
165 This function gets the pointer to the next variable header according
166 to the input point to the variable header.
168 @param Variable Pointer to header of the next variable
170 @return Pointer to next variable header.
175 IN VARIABLE_HEADER
*Variable
178 VARIABLE_HEADER
*VarHeader
;
180 if (Variable
->StartId
!= VARIABLE_DATA
) {
184 // Be careful about pad size for alignment
186 VarHeader
= (VARIABLE_HEADER
*) (GetVariableDataPtr (Variable
) + Variable
->DataSize
+ GET_PAD_SIZE (Variable
->DataSize
));
188 if (VarHeader
->StartId
!= VARIABLE_DATA
) {
196 Gets pointer to the end of the variable storage area.
198 This function gets pointer to the end of the variable storage
199 area, according to the input variable store header.
201 @param VolHeader Pointer to the variale store header
203 @return Pointer to the end of the variable storage area.
208 IN VARIABLE_STORE_HEADER
*VolHeader
212 // The end of variable store
214 return (VARIABLE_HEADER
*) ((UINTN
) VolHeader
+ VolHeader
->Size
);
218 Routine used to track statistical information about variable usage.
219 The data is stored in the EFI system table so it can be accessed later.
220 VariableInfo.efi can dump out the table. Only Boot Services variable
221 accesses are tracked by this code. The PcdVariableCollectStatistics
222 build flag controls if this feature is enabled.
224 A read that hits in the cache will have Read and Cache true for
225 the transaction. Data is allocated by this routine, but never
228 @param[in] VariableName Name of the Variable to track
229 @param[in] VendorGuid Guid of the Variable to track
230 @param[in] Volatile TRUE if volatile FALSE if non-volatile
231 @param[in] Read TRUE if GetVariable() was called
232 @param[in] Write TRUE if SetVariable() was called
233 @param[in] Delete TRUE if deleted via SetVariable()
234 @param[in] Cache TRUE for a cache hit.
239 IN CHAR16
*VariableName
,
240 IN EFI_GUID
*VendorGuid
,
248 VARIABLE_INFO_ENTRY
*Entry
;
250 if (FeaturePcdGet (PcdVariableCollectStatistics
)) {
252 if (EfiAtRuntime ()) {
253 // Don't collect statistics at runtime
257 if (gVariableInfo
== NULL
) {
259 // on the first call allocate a entry and place a pointer to it in
260 // the EFI System Table
262 gVariableInfo
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
263 ASSERT (gVariableInfo
!= NULL
);
265 CopyGuid (&gVariableInfo
->VendorGuid
, VendorGuid
);
266 gVariableInfo
->Name
= AllocatePool (StrLen (VariableName
));
267 ASSERT (gVariableInfo
->Name
!= NULL
);
268 StrCpy (gVariableInfo
->Name
, VariableName
);
269 gVariableInfo
->Volatile
= Volatile
;
271 gBS
->InstallConfigurationTable (&gEfiVariableGuid
, gVariableInfo
);
275 for (Entry
= gVariableInfo
; Entry
!= NULL
; Entry
= Entry
->Next
) {
276 if (CompareGuid (VendorGuid
, &Entry
->VendorGuid
)) {
277 if (StrCmp (VariableName
, Entry
->Name
) == 0) {
285 Entry
->DeleteCount
++;
295 if (Entry
->Next
== NULL
) {
297 // If the entry is not in the table add it.
298 // Next iteration of the loop will fill in the data
300 Entry
->Next
= AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY
));
301 ASSERT (Entry
->Next
!= NULL
);
303 CopyGuid (&Entry
->Next
->VendorGuid
, VendorGuid
);
304 Entry
->Next
->Name
= AllocatePool (StrLen (VariableName
));
305 ASSERT (Entry
->Next
->Name
!= NULL
);
306 StrCpy (Entry
->Next
->Name
, VariableName
);
307 Entry
->Next
->Volatile
= Volatile
;
315 Get index from supported language codes according to language string.
317 This code is used to get corresponding index in supported language codes. It can handle
318 RFC3066 and ISO639 language tags.
319 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
320 In RFC3066 language tags, take semicolon as a delimitation to find matched string and calculate the index.
323 SupportedLang = "engfraengfra"
325 Iso639Language = TRUE
326 The return value is "0".
328 SupportedLang = "en;fr;en-US;fr-FR"
330 Iso639Language = FALSE
331 The return value is "3".
333 @param SupportedLang Platform supported language codes.
334 @param Lang Configured language.
335 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC3066.
337 @retval the index of language in the language codes.
342 GetIndexFromSupportedLangCodes(
343 IN CHAR8
*SupportedLang
,
345 IN BOOLEAN Iso639Language
349 UINT32 CompareLength
;
353 Supported
= SupportedLang
;
354 if (Iso639Language
) {
356 for (Index
= 0; Index
< AsciiStrLen (SupportedLang
); Index
+= CompareLength
) {
357 if (AsciiStrnCmp (Lang
, SupportedLang
+ Index
, CompareLength
) == 0) {
359 // Successfully find the index of Lang string in SupportedLang string.
361 Index
= Index
/ CompareLength
;
369 // Compare RFC3066 language code
371 while (*Supported
!= '\0') {
373 // take semicolon as delimitation, sequentially traverse supported language codes.
375 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
378 if (AsciiStrnCmp (Lang
, Supported
- CompareLength
, CompareLength
) == 0) {
380 // Successfully find the index of Lang string in SupportedLang string.
392 Get language string from supported language codes according to index.
394 This code is used to get corresponding language string in supported language codes. It can handle
395 RFC3066 and ISO639 language tags.
396 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
397 In RFC3066 language tags, take semicolon as a delimitation. Find language string according to the index.
400 SupportedLang = "engfraengfra"
402 Iso639Language = TRUE
403 The return value is "fra".
405 SupportedLang = "en;fr;en-US;fr-FR"
407 Iso639Language = FALSE
408 The return value is "fr".
410 @param SupportedLang Platform supported language codes.
411 @param Index the index in supported language codes.
412 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC3066.
414 @retval the language string in the language codes.
419 GetLangFromSupportedLangCodes (
420 IN CHAR8
*SupportedLang
,
422 IN BOOLEAN Iso639Language
426 UINT32 CompareLength
;
430 Supported
= SupportedLang
;
431 if (Iso639Language
) {
433 // according to the index of Lang string in SupportedLang string to get the language.
434 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
435 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
438 SetMem (mVariableModuleGlobal
->Lang
, sizeof(mVariableModuleGlobal
->Lang
), 0);
439 return CopyMem (mVariableModuleGlobal
->Lang
, SupportedLang
+ Index
* CompareLength
, CompareLength
);
444 // take semicolon as delimitation, sequentially traverse supported language codes.
446 for (CompareLength
= 0; *Supported
!= ';' && *Supported
!= '\0'; CompareLength
++) {
449 if ((*Supported
== '\0') && (SubIndex
!= Index
)) {
451 // Have completed the traverse, but not find corrsponding string.
452 // This case is not allowed to happen.
457 if (SubIndex
== Index
) {
459 // according to the index of Lang string in SupportedLang string to get the language.
460 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
461 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
463 SetMem (mVariableModuleGlobal
->PlatformLang
, sizeof (mVariableModuleGlobal
->PlatformLang
), 0);
464 return CopyMem (mVariableModuleGlobal
->PlatformLang
, Supported
- CompareLength
, CompareLength
);
472 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
474 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
476 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
477 and are read-only. Therefore, in variable driver, only store the original value for other use.
479 @param[in] VariableName Name of variable
481 @param[in] Data Variable data
483 @param[in] DataSize Size of data. 0 means delete
485 @retval EFI_SUCCESS auto update operation is successful.
490 AutoUpdateLangVariable(
491 IN CHAR16
*VariableName
,
497 CHAR8
*BestPlatformLang
;
501 VARIABLE_POINTER_TRACK Variable
;
504 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
506 Attributes
= EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
;
508 if (StrCmp (VariableName
, L
"PlatformLangCodes") == 0) {
510 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
511 // Therefore, in variable driver, only store the original value for other use.
513 AsciiStrnCpy (mVariableModuleGlobal
->PlatformLangCodes
, Data
, DataSize
);
514 } else if (StrCmp (VariableName
, L
"LangCodes") == 0) {
516 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
517 // Therefore, in variable driver, only store the original value for other use.
519 AsciiStrnCpy (mVariableModuleGlobal
->LangCodes
, Data
, DataSize
);
520 } else if (StrCmp (VariableName
, L
"PlatformLang") == 0) {
521 ASSERT (AsciiStrLen (mVariableModuleGlobal
->PlatformLangCodes
) != 0);
524 // When setting PlatformLang, firstly get most matched language string from supported language codes.
526 BestPlatformLang
= GetBestLanguage(mVariableModuleGlobal
->PlatformLangCodes
, FALSE
, Data
, NULL
);
529 // Get the corresponding index in language codes.
531 Index
= GetIndexFromSupportedLangCodes(mVariableModuleGlobal
->PlatformLangCodes
, BestPlatformLang
, FALSE
);
534 // Get the corresponding ISO639 language tag according to RFC3066 language tag.
536 BestLang
= GetLangFromSupportedLangCodes(mVariableModuleGlobal
->LangCodes
, Index
, TRUE
);
539 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
541 FindVariable(L
"Lang", &gEfiGlobalVariableGuid
, &Variable
, (VARIABLE_GLOBAL
*)mVariableModuleGlobal
);
543 Status
= UpdateVariable(L
"Lang", &gEfiGlobalVariableGuid
,
544 BestLang
, ISO_639_2_ENTRY_SIZE
+ 1, Attributes
, &Variable
);
546 DEBUG((EFI_D_INFO
, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang
, BestLang
));
548 ASSERT_EFI_ERROR(Status
);
550 } else if (StrCmp (VariableName
, L
"Lang") == 0) {
551 ASSERT (AsciiStrLen (mVariableModuleGlobal
->LangCodes
) != 0);
554 // When setting Lang, firstly get most matched language string from supported language codes.
556 BestLang
= GetBestLanguage(mVariableModuleGlobal
->LangCodes
, TRUE
, Data
, NULL
);
559 // Get the corresponding index in language codes.
561 Index
= GetIndexFromSupportedLangCodes(mVariableModuleGlobal
->LangCodes
, BestLang
, TRUE
);
564 // Get the corresponding RFC3066 language tag according to ISO639 language tag.
566 BestPlatformLang
= GetLangFromSupportedLangCodes(mVariableModuleGlobal
->PlatformLangCodes
, Index
, FALSE
);
569 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
571 FindVariable(L
"PlatformLang", &gEfiGlobalVariableGuid
, &Variable
, (VARIABLE_GLOBAL
*)mVariableModuleGlobal
);
573 Status
= UpdateVariable(L
"PlatformLang", &gEfiGlobalVariableGuid
,
574 BestPlatformLang
, AsciiStrLen (BestPlatformLang
), Attributes
, &Variable
);
576 DEBUG((EFI_D_INFO
, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang
, BestPlatformLang
));
577 ASSERT_EFI_ERROR(Status
);
583 Update the variable region with Variable information. These are the same
584 arguments as the EFI Variable services.
586 @param[in] VariableName Name of variable
588 @param[in] VendorGuid Guid of variable
590 @param[in] Data Variable data
592 @param[in] DataSize Size of data. 0 means delete
594 @param[in] Attributes Attribues of the variable
596 @param[in] Variable The variable information which is used to keep track of variable usage.
598 @retval EFI_SUCCESS The update operation is success.
600 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
606 IN CHAR16
*VariableName
,
607 IN EFI_GUID
*VendorGuid
,
610 IN UINT32 Attributes OPTIONAL
,
611 IN VARIABLE_POINTER_TRACK
*Variable
615 VARIABLE_HEADER
*NextVariable
;
620 VARIABLE_GLOBAL
*Global
;
621 UINTN NonVolatileVarableStoreSize
;
623 Global
= &mVariableModuleGlobal
->VariableGlobal
[Physical
];
625 if (Variable
->CurrPtr
!= NULL
) {
627 // Update/Delete existing variable
630 if (EfiAtRuntime ()) {
632 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
633 // the volatile is ReadOnly, and SetVariable should be aborted and
634 // return EFI_WRITE_PROTECTED.
636 if (Variable
->Volatile
) {
637 Status
= EFI_WRITE_PROTECTED
;
641 // Only variable have NV attribute can be updated/deleted in Runtime
643 if ((Variable
->CurrPtr
->Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
644 Status
= EFI_INVALID_PARAMETER
;
650 // Setting a data variable with no access, or zero DataSize attributes
651 // specified causes it to be deleted.
653 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
654 Variable
->CurrPtr
->State
&= VAR_DELETED
;
655 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, FALSE
, TRUE
, FALSE
);
656 Status
= EFI_SUCCESS
;
661 // If the variable is marked valid and the same data has been passed in
662 // then return to the caller immediately.
664 if (Variable
->CurrPtr
->DataSize
== DataSize
&&
665 CompareMem (Data
, GetVariableDataPtr (Variable
->CurrPtr
), DataSize
) == 0
667 Status
= EFI_SUCCESS
;
669 } else if (Variable
->CurrPtr
->State
== VAR_ADDED
) {
671 // Mark the old variable as in delete transition
673 Variable
->CurrPtr
->State
&= VAR_IN_DELETED_TRANSITION
;
678 // No found existing variable, Create a new variable
682 // Make sure we are trying to create a new variable.
683 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
685 if (DataSize
== 0 || (Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == 0) {
686 Status
= EFI_NOT_FOUND
;
691 // Only variable have NV|RT attribute can be created in Runtime
693 if (EfiAtRuntime () &&
694 (((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0) || ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0))) {
695 Status
= EFI_INVALID_PARAMETER
;
701 // Function part - create a new variable and copy the data.
702 // Both update a variable and create a variable will come here.
705 VarNameOffset
= sizeof (VARIABLE_HEADER
);
706 VarNameSize
= StrSize (VariableName
);
707 VarDataOffset
= VarNameOffset
+ VarNameSize
+ GET_PAD_SIZE (VarNameSize
);
708 VarSize
= VarDataOffset
+ DataSize
+ GET_PAD_SIZE (DataSize
);
710 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
711 NonVolatileVarableStoreSize
= ((VARIABLE_STORE_HEADER
*)(UINTN
)(Global
->NonVolatileVariableBase
))->Size
;
712 if ((((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0)
713 && ((VarSize
+ mVariableModuleGlobal
->HwErrVariableTotalSize
) > FixedPcdGet32(PcdHwErrStorageSize
)))
714 || (((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == 0)
715 && ((VarSize
+ mVariableModuleGlobal
->CommonVariableTotalSize
) > NonVolatileVarableStoreSize
- sizeof (VARIABLE_STORE_HEADER
) - FixedPcdGet32(PcdHwErrStorageSize
)))) {
716 Status
= EFI_OUT_OF_RESOURCES
;
720 NextVariable
= (VARIABLE_HEADER
*) (UINT8
*) (mVariableModuleGlobal
->NonVolatileLastVariableOffset
721 + (UINTN
) Global
->NonVolatileVariableBase
);
722 mVariableModuleGlobal
->NonVolatileLastVariableOffset
+= VarSize
;
724 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) != 0) {
725 mVariableModuleGlobal
->HwErrVariableTotalSize
+= VarSize
;
727 mVariableModuleGlobal
->CommonVariableTotalSize
+= VarSize
;
730 if ((UINT32
) (VarSize
+ mVariableModuleGlobal
->VolatileLastVariableOffset
) >
731 ((VARIABLE_STORE_HEADER
*) ((UINTN
) (Global
->VolatileVariableBase
)))->Size
733 Status
= EFI_OUT_OF_RESOURCES
;
737 NextVariable
= (VARIABLE_HEADER
*) (UINT8
*) (mVariableModuleGlobal
->VolatileLastVariableOffset
738 + (UINTN
) Global
->VolatileVariableBase
);
739 mVariableModuleGlobal
->VolatileLastVariableOffset
+= VarSize
;
742 NextVariable
->StartId
= VARIABLE_DATA
;
743 NextVariable
->Attributes
= Attributes
;
744 NextVariable
->State
= VAR_ADDED
;
745 NextVariable
->Reserved
= 0;
748 // There will be pad bytes after Data, the NextVariable->NameSize and
749 // NextVariable->NameSize should not include pad size so that variable
750 // service can get actual size in GetVariable
752 NextVariable
->NameSize
= (UINT32
)VarNameSize
;
753 NextVariable
->DataSize
= (UINT32
)DataSize
;
755 CopyMem (&NextVariable
->VendorGuid
, VendorGuid
, sizeof (EFI_GUID
));
757 (UINT8
*) ((UINTN
) NextVariable
+ VarNameOffset
),
762 (UINT8
*) ((UINTN
) NextVariable
+ VarDataOffset
),
768 // Mark the old variable as deleted
770 Variable
->CurrPtr
->State
&= VAR_DELETED
;
772 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
->Volatile
, FALSE
, TRUE
, FALSE
, FALSE
);
774 Status
= EFI_SUCCESS
;
781 Finds variable in storage blocks of volatile and non-volatile storage areas.
783 This code finds variable in storage blocks of volatile and non-volatile storage areas.
784 If VariableName is an empty string, then we just return the first
785 qualified variable without comparing VariableName and VendorGuid.
786 Otherwise, VariableName and VendorGuid are compared.
788 @param VariableName Name of the variable to be found.
789 @param VendorGuid Vendor GUID to be found.
790 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
791 including the range searched and the target position.
792 @param Global Pointer to VARIABLE_GLOBAL structure, including
793 base of volatile variable storage area, base of
794 NV variable storage area, and a lock.
796 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
798 @retval EFI_SUCCESS Variable successfully found.
799 @retval EFI_NOT_FOUND Variable not found.
804 IN CHAR16
*VariableName
,
805 IN EFI_GUID
*VendorGuid
,
806 OUT VARIABLE_POINTER_TRACK
*PtrTrack
,
807 IN VARIABLE_GLOBAL
*Global
810 VARIABLE_HEADER
*Variable
[2];
811 VARIABLE_STORE_HEADER
*VariableStoreHeader
[2];
815 // 0: Non-Volatile, 1: Volatile
817 VariableStoreHeader
[0] = (VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->NonVolatileVariableBase
);
818 VariableStoreHeader
[1] = (VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->VolatileVariableBase
);
821 // Start Pointers for the variable.
822 // Actual Data Pointer where data can be written.
824 Variable
[0] = (VARIABLE_HEADER
*) (VariableStoreHeader
[0] + 1);
825 Variable
[1] = (VARIABLE_HEADER
*) (VariableStoreHeader
[1] + 1);
827 if (VariableName
[0] != 0 && VendorGuid
== NULL
) {
828 return EFI_INVALID_PARAMETER
;
831 // Find the variable by walk through non-volatile and volatile variable store
833 for (Index
= 0; Index
< 2; Index
++) {
834 PtrTrack
->StartPtr
= (VARIABLE_HEADER
*) (VariableStoreHeader
[Index
] + 1);
835 PtrTrack
->EndPtr
= GetEndPointer (VariableStoreHeader
[Index
]);
837 while ((Variable
[Index
] < GetEndPointer (VariableStoreHeader
[Index
])) && (Variable
[Index
] != NULL
)) {
838 if (Variable
[Index
]->StartId
== VARIABLE_DATA
&& Variable
[Index
]->State
== VAR_ADDED
) {
839 if (!(EfiAtRuntime () && ((Variable
[Index
]->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0))) {
840 if (VariableName
[0] == 0) {
841 PtrTrack
->CurrPtr
= Variable
[Index
];
842 PtrTrack
->Volatile
= (BOOLEAN
) Index
;
845 if (CompareGuid (VendorGuid
, &Variable
[Index
]->VendorGuid
)) {
846 if (CompareMem (VariableName
, GET_VARIABLE_NAME_PTR (Variable
[Index
]), Variable
[Index
]->NameSize
) == 0) {
847 PtrTrack
->CurrPtr
= Variable
[Index
];
848 PtrTrack
->Volatile
= (BOOLEAN
) Index
;
856 Variable
[Index
] = GetNextVariablePtr (Variable
[Index
]);
859 PtrTrack
->CurrPtr
= NULL
;
860 return EFI_NOT_FOUND
;
864 This code finds variable in storage blocks (Volatile or Non-Volatile).
866 @param VariableName A Null-terminated Unicode string that is the name of
867 the vendor's variable.
868 @param VendorGuid A unique identifier for the vendor.
869 @param Attributes If not NULL, a pointer to the memory location to return the
870 attributes bitmask for the variable.
871 @param DataSize Size of Data found. If size is less than the
872 data, this value contains the required size.
873 @param Data On input, the size in bytes of the return Data buffer.
874 On output, the size of data returned in Data.
875 @param Global Pointer to VARIABLE_GLOBAL structure
877 @retval EFI_SUCCESS The function completed successfully.
878 @retval EFI_NOT_FOUND The variable was not found.
879 @retval EFI_BUFFER_TOO_SMALL DataSize is too small for the result. DataSize has
880 been updated with the size needed to complete the request.
881 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid or DataSize is NULL.
887 IN CHAR16
*VariableName
,
888 IN EFI_GUID
*VendorGuid
,
889 OUT UINT32
*Attributes OPTIONAL
,
890 IN OUT UINTN
*DataSize
,
892 IN VARIABLE_GLOBAL
*Global
895 VARIABLE_POINTER_TRACK Variable
;
899 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
900 return EFI_INVALID_PARAMETER
;
903 AcquireLockOnlyAtBootTime(&Global
->VariableServicesLock
);
906 // Find existing variable
908 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, Global
);
910 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
916 VarDataSize
= Variable
.CurrPtr
->DataSize
;
917 if (*DataSize
>= VarDataSize
) {
919 Status
= EFI_INVALID_PARAMETER
;
923 CopyMem (Data
, GetVariableDataPtr (Variable
.CurrPtr
), VarDataSize
);
924 if (Attributes
!= NULL
) {
925 *Attributes
= Variable
.CurrPtr
->Attributes
;
928 *DataSize
= VarDataSize
;
929 UpdateVariableInfo (VariableName
, VendorGuid
, Variable
.Volatile
, TRUE
, FALSE
, FALSE
, FALSE
);
930 Status
= EFI_SUCCESS
;
933 *DataSize
= VarDataSize
;
934 Status
= EFI_BUFFER_TOO_SMALL
;
939 ReleaseLockOnlyAtBootTime (&Global
->VariableServicesLock
);
945 This code Finds the Next available variable.
947 @param VariableNameSize Size of the variable.
948 @param VariableName On input, supplies the last VariableName that was returned by GetNextVariableName().
949 On output, returns the Null-terminated Unicode string of the current variable.
950 @param VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName().
951 On output, returns the VendorGuid of the current variable.
952 @param Global Pointer to VARIABLE_GLOBAL structure.
954 @retval EFI_SUCCESS The function completed successfully.
955 @retval EFI_NOT_FOUND The next variable was not found.
956 @retval EFI_BUFFER_TOO_SMALL VariableNameSize is too small for the result.
957 VariableNameSize has been updated with the size needed to complete the request.
958 @retval EFI_INVALID_PARAMETER VariableNameSize or VariableName or VendorGuid is NULL.
963 EmuGetNextVariableName (
964 IN OUT UINTN
*VariableNameSize
,
965 IN OUT CHAR16
*VariableName
,
966 IN OUT EFI_GUID
*VendorGuid
,
967 IN VARIABLE_GLOBAL
*Global
970 VARIABLE_POINTER_TRACK Variable
;
974 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
975 return EFI_INVALID_PARAMETER
;
978 AcquireLockOnlyAtBootTime(&Global
->VariableServicesLock
);
980 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, Global
);
982 if (Variable
.CurrPtr
== NULL
|| EFI_ERROR (Status
)) {
987 if (VariableName
[0] != 0) {
989 // If variable name is not NULL, get next variable
991 Variable
.CurrPtr
= GetNextVariablePtr (Variable
.CurrPtr
);
994 // If both volatile and non-volatile variable store are parsed,
997 if (Variable
.CurrPtr
>= Variable
.EndPtr
|| Variable
.CurrPtr
== NULL
) {
998 Variable
.Volatile
= (BOOLEAN
) (Variable
.Volatile
^ ((BOOLEAN
) 0x1));
999 if (Variable
.Volatile
) {
1000 Variable
.StartPtr
= (VARIABLE_HEADER
*) ((UINTN
) (Global
->VolatileVariableBase
+ sizeof (VARIABLE_STORE_HEADER
)));
1001 Variable
.EndPtr
= (VARIABLE_HEADER
*) GetEndPointer ((VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->VolatileVariableBase
));
1003 Status
= EFI_NOT_FOUND
;
1007 Variable
.CurrPtr
= Variable
.StartPtr
;
1008 if (Variable
.CurrPtr
->StartId
!= VARIABLE_DATA
) {
1013 // Variable is found
1015 if (Variable
.CurrPtr
->StartId
== VARIABLE_DATA
&& Variable
.CurrPtr
->State
== VAR_ADDED
) {
1016 if (!(EfiAtRuntime () && ((Variable
.CurrPtr
->Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0))) {
1017 VarNameSize
= Variable
.CurrPtr
->NameSize
;
1018 if (VarNameSize
<= *VariableNameSize
) {
1021 GET_VARIABLE_NAME_PTR (Variable
.CurrPtr
),
1026 &Variable
.CurrPtr
->VendorGuid
,
1029 Status
= EFI_SUCCESS
;
1031 Status
= EFI_BUFFER_TOO_SMALL
;
1034 *VariableNameSize
= VarNameSize
;
1041 ReleaseLockOnlyAtBootTime (&Global
->VariableServicesLock
);
1048 This code sets variable in storage blocks (Volatile or Non-Volatile).
1050 @param VariableName A Null-terminated Unicode string that is the name of the vendor's
1051 variable. Each VariableName is unique for each
1052 VendorGuid. VariableName must contain 1 or more
1053 Unicode characters. If VariableName is an empty Unicode
1054 string, then EFI_INVALID_PARAMETER is returned.
1055 @param VendorGuid A unique identifier for the vendor
1056 @param Attributes Attributes bitmask to set for the variable
1057 @param DataSize The size in bytes of the Data buffer. A size of zero causes the
1058 variable to be deleted.
1059 @param Data The contents for the variable
1060 @param Global Pointer to VARIABLE_GLOBAL structure
1061 @param VolatileOffset The offset of last volatile variable
1062 @param NonVolatileOffset The offset of last non-volatile variable
1064 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
1065 defined by the Attributes.
1066 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
1067 DataSize exceeds the maximum allowed, or VariableName is an empty
1068 Unicode string, or VendorGuid is NULL.
1069 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
1070 @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.
1071 @retval EFI_WRITE_PROTECTED The variable in question is read-only or cannot be deleted.
1072 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
1078 IN CHAR16
*VariableName
,
1079 IN EFI_GUID
*VendorGuid
,
1080 IN UINT32 Attributes
,
1083 IN VARIABLE_GLOBAL
*Global
,
1084 IN UINTN
*VolatileOffset
,
1085 IN UINTN
*NonVolatileOffset
1088 VARIABLE_POINTER_TRACK Variable
;
1092 // Check input parameters
1094 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
1095 return EFI_INVALID_PARAMETER
;
1098 // Make sure if runtime bit is set, boot service bit is set also
1100 if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1101 return EFI_INVALID_PARAMETER
;
1104 // The size of the VariableName, including the Unicode Null in bytes plus
1105 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)
1106 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.
1108 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1109 if ((DataSize
> FixedPcdGet32(PcdMaxHardwareErrorVariableSize
)) ||
1110 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> FixedPcdGet32(PcdMaxHardwareErrorVariableSize
))) {
1111 return EFI_INVALID_PARAMETER
;
1114 // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"
1116 if (StrnCmp(VariableName
, L
"HwErrRec", StrLen(L
"HwErrRec")) != 0) {
1117 return EFI_INVALID_PARAMETER
;
1121 // The size of the VariableName, including the Unicode Null in bytes plus
1122 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.
1124 if ((DataSize
> FixedPcdGet32(PcdMaxVariableSize
)) ||
1125 (sizeof (VARIABLE_HEADER
) + StrSize (VariableName
) + DataSize
> FixedPcdGet32(PcdMaxVariableSize
))) {
1126 return EFI_INVALID_PARAMETER
;
1130 AcquireLockOnlyAtBootTime(&Global
->VariableServicesLock
);
1133 // Check whether the input variable is already existed
1136 Status
= FindVariable (VariableName
, VendorGuid
, &Variable
, Global
);
1139 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang
1141 AutoUpdateLangVariable (VariableName
, Data
, DataSize
);
1143 Status
= UpdateVariable (VariableName
, VendorGuid
, Data
, DataSize
, Attributes
, &Variable
);
1145 ReleaseLockOnlyAtBootTime (&Global
->VariableServicesLock
);
1151 This code returns information about the EFI variables.
1153 @param Attributes Attributes bitmask to specify the type of variables
1154 on which to return information.
1155 @param MaximumVariableStorageSize On output the maximum size of the storage space available for
1156 the EFI variables associated with the attributes specified.
1157 @param RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI
1158 variables associated with the attributes specified.
1159 @param MaximumVariableSize Returns the maximum size of an individual EFI variable
1160 associated with the attributes specified.
1161 @param Global Pointer to VARIABLE_GLOBAL structure.
1163 @retval EFI_SUCCESS Valid answer returned.
1164 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied
1165 @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the
1166 MaximumVariableStorageSize, RemainingVariableStorageSize,
1167 MaximumVariableSize are undefined.
1172 EmuQueryVariableInfo (
1173 IN UINT32 Attributes
,
1174 OUT UINT64
*MaximumVariableStorageSize
,
1175 OUT UINT64
*RemainingVariableStorageSize
,
1176 OUT UINT64
*MaximumVariableSize
,
1177 IN VARIABLE_GLOBAL
*Global
1180 VARIABLE_HEADER
*Variable
;
1181 VARIABLE_HEADER
*NextVariable
;
1182 UINT64 VariableSize
;
1183 VARIABLE_STORE_HEADER
*VariableStoreHeader
;
1184 UINT64 CommonVariableTotalSize
;
1185 UINT64 HwErrVariableTotalSize
;
1187 CommonVariableTotalSize
= 0;
1188 HwErrVariableTotalSize
= 0;
1190 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
1191 return EFI_INVALID_PARAMETER
;
1194 if((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == 0) {
1196 // Make sure the Attributes combination is supported by the platform.
1198 return EFI_UNSUPPORTED
;
1199 } else if ((Attributes
& (EFI_VARIABLE_RUNTIME_ACCESS
| EFI_VARIABLE_BOOTSERVICE_ACCESS
)) == EFI_VARIABLE_RUNTIME_ACCESS
) {
1201 // Make sure if runtime bit is set, boot service bit is set also.
1203 return EFI_INVALID_PARAMETER
;
1204 } else if (EfiAtRuntime () && ((Attributes
& EFI_VARIABLE_RUNTIME_ACCESS
) == 0)) {
1206 // Make sure RT Attribute is set if we are in Runtime phase.
1208 return EFI_INVALID_PARAMETER
;
1209 } else if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1211 // Make sure Hw Attribute is set with NV.
1213 return EFI_INVALID_PARAMETER
;
1216 AcquireLockOnlyAtBootTime(&Global
->VariableServicesLock
);
1218 if((Attributes
& EFI_VARIABLE_NON_VOLATILE
) == 0) {
1220 // Query is Volatile related.
1222 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->VolatileVariableBase
);
1225 // Query is Non-Volatile related.
1227 VariableStoreHeader
= (VARIABLE_STORE_HEADER
*) ((UINTN
) Global
->NonVolatileVariableBase
);
1231 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1232 // with the storage size (excluding the storage header size)
1234 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
);
1237 // Harware error record variable needs larger size.
1239 if ((Attributes
& (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) == (EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_HARDWARE_ERROR_RECORD
)) {
1240 *MaximumVariableStorageSize
= FixedPcdGet32(PcdHwErrStorageSize
);
1241 *MaximumVariableSize
= FixedPcdGet32(PcdMaxHardwareErrorVariableSize
) - sizeof (VARIABLE_HEADER
);
1243 if ((Attributes
& EFI_VARIABLE_NON_VOLATILE
) != 0) {
1244 ASSERT (FixedPcdGet32(PcdHwErrStorageSize
) < VariableStoreHeader
->Size
);
1245 *MaximumVariableStorageSize
= VariableStoreHeader
->Size
- sizeof (VARIABLE_STORE_HEADER
) - FixedPcdGet32(PcdHwErrStorageSize
);
1249 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
1251 *MaximumVariableSize
= FixedPcdGet32(PcdMaxVariableSize
) - sizeof (VARIABLE_HEADER
);
1255 // Point to the starting address of the variables.
1257 Variable
= (VARIABLE_HEADER
*) (VariableStoreHeader
+ 1);
1260 // Now walk through the related variable store.
1262 while (Variable
< GetEndPointer (VariableStoreHeader
)) {
1263 NextVariable
= GetNextVariablePtr(Variable
);
1264 if (NextVariable
== NULL
) {
1267 VariableSize
= (UINT64
) (UINTN
) NextVariable
- (UINT64
) (UINTN
) Variable
;
1269 if ((NextVariable
->Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
) {
1270 HwErrVariableTotalSize
+= VariableSize
;
1272 CommonVariableTotalSize
+= VariableSize
;
1276 // Go to the next one.
1278 Variable
= NextVariable
;
1281 if ((Attributes
& EFI_VARIABLE_HARDWARE_ERROR_RECORD
) == EFI_VARIABLE_HARDWARE_ERROR_RECORD
){
1282 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- HwErrVariableTotalSize
;
1284 *RemainingVariableStorageSize
= *MaximumVariableStorageSize
- CommonVariableTotalSize
;
1287 if (*RemainingVariableStorageSize
< sizeof (VARIABLE_HEADER
)) {
1288 *MaximumVariableSize
= 0;
1289 } else if ((*RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
)) < *MaximumVariableSize
) {
1290 *MaximumVariableSize
= *RemainingVariableStorageSize
- sizeof (VARIABLE_HEADER
);
1293 ReleaseLockOnlyAtBootTime (&Global
->VariableServicesLock
);
1298 Initializes variable store area.
1300 This function allocates memory space for variable store area and initializes its attributes.
1302 @param VariableBase Base of the variable store area created
1303 @param LastVariableOffset Size of VARIABLE_STORE_HEADER
1307 InitializeVariableStore (
1308 OUT EFI_PHYSICAL_ADDRESS
*VariableBase
,
1309 OUT UINTN
*LastVariableOffset
1312 VARIABLE_STORE_HEADER
*VariableStore
;
1315 // Allocate memory for volatile variable store
1317 VariableStore
= (VARIABLE_STORE_HEADER
*) AllocateRuntimePool (
1318 FixedPcdGet32(PcdVariableStoreSize
)
1320 if (NULL
== VariableStore
) {
1321 return EFI_OUT_OF_RESOURCES
;
1324 SetMem (VariableStore
, FixedPcdGet32(PcdVariableStoreSize
), 0xff);
1327 // Variable Specific Data
1329 *VariableBase
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) VariableStore
;
1330 *LastVariableOffset
= sizeof (VARIABLE_STORE_HEADER
);
1332 CopyGuid (&VariableStore
->Signature
, &gEfiVariableGuid
);
1333 VariableStore
->Size
= FixedPcdGet32(PcdVariableStoreSize
);
1334 VariableStore
->Format
= VARIABLE_STORE_FORMATTED
;
1335 VariableStore
->State
= VARIABLE_STORE_HEALTHY
;
1336 VariableStore
->Reserved
= 0;
1337 VariableStore
->Reserved1
= 0;
1343 Initializes variable store area for non-volatile and volatile variable.
1345 This function allocates and initializes memory space for global context of ESAL
1346 variable service and variable store area for non-volatile and volatile variable.
1348 @param ImageHandle The Image handle of this driver.
1349 @param SystemTable The pointer of EFI_SYSTEM_TABLE.
1351 @retval EFI_SUCCESS Function successfully executed.
1352 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
1357 VariableCommonInitialize (
1358 IN EFI_HANDLE ImageHandle
,
1359 IN EFI_SYSTEM_TABLE
*SystemTable
1365 // Allocate memory for mVariableModuleGlobal
1367 mVariableModuleGlobal
= (ESAL_VARIABLE_GLOBAL
*) AllocateRuntimeZeroPool (
1368 sizeof (ESAL_VARIABLE_GLOBAL
)
1370 if (NULL
== mVariableModuleGlobal
) {
1371 return EFI_OUT_OF_RESOURCES
;
1374 EfiInitializeLock(&mVariableModuleGlobal
->VariableGlobal
[Physical
].VariableServicesLock
, TPL_NOTIFY
);
1377 // Intialize volatile variable store
1379 Status
= InitializeVariableStore (
1380 &mVariableModuleGlobal
->VariableGlobal
[Physical
].VolatileVariableBase
,
1381 &mVariableModuleGlobal
->VolatileLastVariableOffset
1384 if (EFI_ERROR (Status
)) {
1385 FreePool(mVariableModuleGlobal
);
1389 // Intialize non volatile variable store
1391 Status
= InitializeVariableStore (
1392 &mVariableModuleGlobal
->VariableGlobal
[Physical
].NonVolatileVariableBase
,
1393 &mVariableModuleGlobal
->NonVolatileLastVariableOffset