2 Implement all four UEFI Runtime Variable services for the nonvolatile
3 and volatile storage space and install variable architecture protocol
4 based on SMM variable module.
6 Caution: This module requires additional review when modified.
7 This driver will have external input - variable data.
8 This external input must be validated carefully to avoid security issue like
9 buffer overflow, integer overflow.
11 RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
12 to receive data buffer. The size should be checked carefully.
14 InitCommunicateBuffer() is really function to check the variable data size.
16 Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
17 SPDX-License-Identifier: BSD-2-Clause-Patent
21 #include <Protocol/VariableWrite.h>
22 #include <Protocol/Variable.h>
23 #include <Protocol/SmmCommunication.h>
24 #include <Protocol/SmmVariable.h>
25 #include <Protocol/VariableLock.h>
26 #include <Protocol/VarCheck.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Library/MemoryAllocationLib.h>
31 #include <Library/UefiDriverEntryPoint.h>
32 #include <Library/UefiRuntimeLib.h>
33 #include <Library/BaseMemoryLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/UefiLib.h>
36 #include <Library/BaseLib.h>
38 #include <Guid/EventGroup.h>
39 #include <Guid/SmmVariableCommon.h>
41 #include "PrivilegePolymorphic.h"
42 #include "VariableParsing.h"
44 EFI_HANDLE mHandle
= NULL
;
45 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
= NULL
;
46 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
47 EFI_SMM_COMMUNICATION_PROTOCOL
*mSmmCommunication
= NULL
;
48 UINT8
*mVariableBuffer
= NULL
;
49 UINT8
*mVariableBufferPhysical
= NULL
;
50 VARIABLE_INFO_ENTRY
*mVariableInfo
= NULL
;
51 VARIABLE_STORE_HEADER
*mVariableRuntimeHobCacheBuffer
= NULL
;
52 VARIABLE_STORE_HEADER
*mVariableRuntimeNvCacheBuffer
= NULL
;
53 VARIABLE_STORE_HEADER
*mVariableRuntimeVolatileCacheBuffer
= NULL
;
54 UINTN mVariableBufferSize
;
55 UINTN mVariableRuntimeHobCacheBufferSize
;
56 UINTN mVariableRuntimeNvCacheBufferSize
;
57 UINTN mVariableRuntimeVolatileCacheBufferSize
;
58 UINTN mVariableBufferPayloadSize
;
59 BOOLEAN mVariableRuntimeCachePendingUpdate
;
60 BOOLEAN mVariableRuntimeCacheReadLock
;
61 BOOLEAN mVariableAuthFormat
;
62 BOOLEAN mHobFlushComplete
;
63 EFI_LOCK mVariableServicesLock
;
64 EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock
;
65 EDKII_VAR_CHECK_PROTOCOL mVarCheck
;
68 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
69 Record their initial State when variable write service is ready.
74 RecordSecureBootPolicyVarData(
79 Acquires lock only at boot time. Simply returns at runtime.
81 This is a temperary function that will be removed when
82 EfiAcquireLock() in UefiLib can handle the call in UEFI
83 Runtimer driver in RT phase.
84 It calls EfiAcquireLock() at boot time, and simply returns
87 @param Lock A pointer to the lock to acquire.
91 AcquireLockOnlyAtBootTime (
95 if (!EfiAtRuntime ()) {
96 EfiAcquireLock (Lock
);
101 Releases lock only at boot time. Simply returns at runtime.
103 This is a temperary function which will be removed when
104 EfiReleaseLock() in UefiLib can handle the call in UEFI
105 Runtimer driver in RT phase.
106 It calls EfiReleaseLock() at boot time and simply returns
109 @param Lock A pointer to the lock to release.
113 ReleaseLockOnlyAtBootTime (
117 if (!EfiAtRuntime ()) {
118 EfiReleaseLock (Lock
);
123 Return TRUE if ExitBootServices () has been called.
125 @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.
132 return EfiAtRuntime ();
136 Initialize the variable cache buffer as an empty variable store.
138 @param[out] VariableCacheBuffer A pointer to pointer of a cache variable store.
139 @param[in,out] TotalVariableCacheSize On input, the minimum size needed for the UEFI variable store cache
140 buffer that is allocated. On output, the actual size of the buffer allocated.
141 If TotalVariableCacheSize is zero, a buffer will not be allocated and the
142 function will return with EFI_SUCCESS.
144 @retval EFI_SUCCESS The variable cache was allocated and initialized successfully.
145 @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid variable store size was specified.
146 @retval EFI_OUT_OF_RESOURCES Insufficient resources are available to allocate the variable store cache buffer.
151 OUT VARIABLE_STORE_HEADER
**VariableCacheBuffer
,
152 IN OUT UINTN
*TotalVariableCacheSize
155 VARIABLE_STORE_HEADER
*VariableCacheStorePtr
;
157 if (TotalVariableCacheSize
== NULL
) {
158 return EFI_INVALID_PARAMETER
;
160 if (*TotalVariableCacheSize
== 0) {
163 if (VariableCacheBuffer
== NULL
|| *TotalVariableCacheSize
< sizeof (VARIABLE_STORE_HEADER
)) {
164 return EFI_INVALID_PARAMETER
;
166 *TotalVariableCacheSize
= ALIGN_VALUE (*TotalVariableCacheSize
, sizeof (UINT32
));
169 // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)
171 *VariableCacheBuffer
= (VARIABLE_STORE_HEADER
*) AllocateRuntimePages (
172 EFI_SIZE_TO_PAGES (*TotalVariableCacheSize
)
174 if (*VariableCacheBuffer
== NULL
) {
175 return EFI_OUT_OF_RESOURCES
;
177 VariableCacheStorePtr
= *VariableCacheBuffer
;
178 SetMem32 ((VOID
*) VariableCacheStorePtr
, *TotalVariableCacheSize
, (UINT32
) 0xFFFFFFFF);
180 ZeroMem ((VOID
*) VariableCacheStorePtr
, sizeof (VARIABLE_STORE_HEADER
));
181 VariableCacheStorePtr
->Size
= (UINT32
) *TotalVariableCacheSize
;
182 VariableCacheStorePtr
->Format
= VARIABLE_STORE_FORMATTED
;
183 VariableCacheStorePtr
->State
= VARIABLE_STORE_HEALTHY
;
189 Initialize the communicate buffer using DataSize and Function.
191 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
194 Caution: This function may receive untrusted input.
195 The data size external input, so this function will validate it carefully to avoid buffer overflow.
197 @param[out] DataPtr Points to the data in the communicate buffer.
198 @param[in] DataSize The data size to send to SMM.
199 @param[in] Function The function number to initialize the communicate header.
201 @retval EFI_INVALID_PARAMETER The data size is too big.
202 @retval EFI_SUCCESS Find the specified variable.
206 InitCommunicateBuffer (
207 OUT VOID
**DataPtr OPTIONAL
,
212 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
213 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
216 if (DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
> mVariableBufferSize
) {
217 return EFI_INVALID_PARAMETER
;
220 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
221 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
222 SmmCommunicateHeader
->MessageLength
= DataSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
224 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
225 SmmVariableFunctionHeader
->Function
= Function
;
226 if (DataPtr
!= NULL
) {
227 *DataPtr
= SmmVariableFunctionHeader
->Data
;
235 Send the data in communicate buffer to SMM.
237 @param[in] DataSize This size of the function header and the data.
239 @retval EFI_SUCCESS Success is returned from the functin in SMM.
240 @retval Others Failure is returned from the function in SMM.
244 SendCommunicateBuffer (
250 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
251 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
253 CommSize
= DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
254 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, mVariableBufferPhysical
, &CommSize
);
255 ASSERT_EFI_ERROR (Status
);
257 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
258 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
259 return SmmVariableFunctionHeader
->ReturnStatus
;
263 Mark a variable that will become read-only after leaving the DXE phase of execution.
265 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
266 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
267 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
269 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
270 as pending to be read-only.
271 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
272 Or VariableName is an empty string.
273 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
274 already been signaled.
275 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
279 VariableLockRequestToLock (
280 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
281 IN CHAR16
*VariableName
,
282 IN EFI_GUID
*VendorGuid
286 UINTN VariableNameSize
;
288 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
290 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
291 return EFI_INVALID_PARAMETER
;
294 VariableNameSize
= StrSize (VariableName
);
295 VariableToLock
= NULL
;
298 // If VariableName exceeds SMM payload limit. Return failure
300 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
)) {
301 return EFI_INVALID_PARAMETER
;
304 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
307 // Init the communicate buffer. The buffer data size is:
308 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
310 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
) + VariableNameSize
;
311 Status
= InitCommunicateBuffer ((VOID
**) &VariableToLock
, PayloadSize
, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
);
312 if (EFI_ERROR (Status
)) {
315 ASSERT (VariableToLock
!= NULL
);
317 CopyGuid (&VariableToLock
->Guid
, VendorGuid
);
318 VariableToLock
->NameSize
= VariableNameSize
;
319 CopyMem (VariableToLock
->Name
, VariableName
, VariableToLock
->NameSize
);
324 Status
= SendCommunicateBuffer (PayloadSize
);
327 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
332 Register SetVariable check handler.
334 @param[in] Handler Pointer to check handler.
336 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
337 @retval EFI_INVALID_PARAMETER Handler is NULL.
338 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
339 already been signaled.
340 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
341 @retval EFI_UNSUPPORTED This interface is not implemented.
342 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
347 VarCheckRegisterSetVariableCheckHandler (
348 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
351 return EFI_UNSUPPORTED
;
355 Variable property set.
357 @param[in] Name Pointer to the variable name.
358 @param[in] Guid Pointer to the vendor GUID.
359 @param[in] VariableProperty Pointer to the input variable property.
361 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
362 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
363 or the fields of VariableProperty are not valid.
364 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
365 already been signaled.
366 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
371 VarCheckVariablePropertySet (
374 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
378 UINTN VariableNameSize
;
380 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
382 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
383 return EFI_INVALID_PARAMETER
;
386 if (VariableProperty
== NULL
) {
387 return EFI_INVALID_PARAMETER
;
390 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
391 return EFI_INVALID_PARAMETER
;
394 VariableNameSize
= StrSize (Name
);
395 CommVariableProperty
= NULL
;
398 // If VariableName exceeds SMM payload limit. Return failure
400 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
401 return EFI_INVALID_PARAMETER
;
404 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
407 // Init the communicate buffer. The buffer data size is:
408 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
410 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
411 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
);
412 if (EFI_ERROR (Status
)) {
415 ASSERT (CommVariableProperty
!= NULL
);
417 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
418 CopyMem (&CommVariableProperty
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
419 CommVariableProperty
->NameSize
= VariableNameSize
;
420 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
425 Status
= SendCommunicateBuffer (PayloadSize
);
428 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
433 Variable property get.
435 @param[in] Name Pointer to the variable name.
436 @param[in] Guid Pointer to the vendor GUID.
437 @param[out] VariableProperty Pointer to the output variable property.
439 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
440 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
441 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
446 VarCheckVariablePropertyGet (
449 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
453 UINTN VariableNameSize
;
455 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
457 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
458 return EFI_INVALID_PARAMETER
;
461 if (VariableProperty
== NULL
) {
462 return EFI_INVALID_PARAMETER
;
465 VariableNameSize
= StrSize (Name
);
466 CommVariableProperty
= NULL
;
469 // If VariableName exceeds SMM payload limit. Return failure
471 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
472 return EFI_INVALID_PARAMETER
;
475 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
478 // Init the communicate buffer. The buffer data size is:
479 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
481 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
482 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
);
483 if (EFI_ERROR (Status
)) {
486 ASSERT (CommVariableProperty
!= NULL
);
488 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
489 CommVariableProperty
->NameSize
= VariableNameSize
;
490 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
495 Status
= SendCommunicateBuffer (PayloadSize
);
496 if (Status
== EFI_SUCCESS
) {
497 CopyMem (VariableProperty
, &CommVariableProperty
->VariableProperty
, sizeof (*VariableProperty
));
501 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
506 Signals SMM to synchronize any pending variable updates with the runtime cache(s).
515 // Init the communicate buffer. The buffer data size is:
516 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
518 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE
);
523 SendCommunicateBuffer (0);
527 Check whether a SMI must be triggered to retrieve pending cache updates.
529 If the variable HOB was finished being flushed since the last check for a runtime cache update, this function
530 will prevent the HOB cache from being used for future runtime cache hits.
534 CheckForRuntimeCacheSync (
538 if (mVariableRuntimeCachePendingUpdate
) {
541 ASSERT (!mVariableRuntimeCachePendingUpdate
);
544 // The HOB variable data may have finished being flushed in the runtime cache sync update
546 if (mHobFlushComplete
&& mVariableRuntimeHobCacheBuffer
!= NULL
) {
547 if (!EfiAtRuntime ()) {
548 FreePages (mVariableRuntimeHobCacheBuffer
, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize
));
550 mVariableRuntimeHobCacheBuffer
= NULL
;
555 Finds the given variable in a runtime cache variable store.
557 Caution: This function may receive untrusted input.
558 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
560 @param[in] VariableName Name of Variable to be found.
561 @param[in] VendorGuid Variable vendor GUID.
562 @param[out] Attributes Attribute value of the variable found.
563 @param[in, out] DataSize Size of Data found. If size is less than the
564 data, this value contains the required size.
565 @param[out] Data Data pointer.
567 @retval EFI_SUCCESS Found the specified variable.
568 @retval EFI_INVALID_PARAMETER Invalid parameter.
569 @retval EFI_NOT_FOUND The specified variable could not be found.
573 FindVariableInRuntimeCache (
574 IN CHAR16
*VariableName
,
575 IN EFI_GUID
*VendorGuid
,
576 OUT UINT32
*Attributes OPTIONAL
,
577 IN OUT UINTN
*DataSize
,
578 OUT VOID
*Data OPTIONAL
583 VARIABLE_POINTER_TRACK RtPtrTrack
;
584 VARIABLE_STORE_TYPE StoreType
;
585 VARIABLE_STORE_HEADER
*VariableStoreList
[VariableStoreTypeMax
];
587 Status
= EFI_NOT_FOUND
;
589 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
590 return EFI_INVALID_PARAMETER
;
593 ZeroMem (&RtPtrTrack
, sizeof (RtPtrTrack
));
596 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
597 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
598 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
599 // cache read lock should always be free when entering this function.
601 ASSERT (!mVariableRuntimeCacheReadLock
);
603 mVariableRuntimeCacheReadLock
= TRUE
;
604 CheckForRuntimeCacheSync ();
606 if (!mVariableRuntimeCachePendingUpdate
) {
608 // 0: Volatile, 1: HOB, 2: Non-Volatile.
609 // The index and attributes mapping must be kept in this order as FindVariable
610 // makes use of this mapping to implement search algorithm.
612 VariableStoreList
[VariableStoreTypeVolatile
] = mVariableRuntimeVolatileCacheBuffer
;
613 VariableStoreList
[VariableStoreTypeHob
] = mVariableRuntimeHobCacheBuffer
;
614 VariableStoreList
[VariableStoreTypeNv
] = mVariableRuntimeNvCacheBuffer
;
616 for (StoreType
= (VARIABLE_STORE_TYPE
) 0; StoreType
< VariableStoreTypeMax
; StoreType
++) {
617 if (VariableStoreList
[StoreType
] == NULL
) {
621 RtPtrTrack
.StartPtr
= GetStartPointer (VariableStoreList
[StoreType
]);
622 RtPtrTrack
.EndPtr
= GetEndPointer (VariableStoreList
[StoreType
]);
623 RtPtrTrack
.Volatile
= (BOOLEAN
) (StoreType
== VariableStoreTypeVolatile
);
625 Status
= FindVariableEx (VariableName
, VendorGuid
, FALSE
, &RtPtrTrack
, mVariableAuthFormat
);
626 if (!EFI_ERROR (Status
)) {
631 if (!EFI_ERROR (Status
)) {
635 TempDataSize
= DataSizeOfVariable (RtPtrTrack
.CurrPtr
, mVariableAuthFormat
);
636 ASSERT (TempDataSize
!= 0);
638 if (*DataSize
>= TempDataSize
) {
640 Status
= EFI_INVALID_PARAMETER
;
644 CopyMem (Data
, GetVariableDataPtr (RtPtrTrack
.CurrPtr
, mVariableAuthFormat
), TempDataSize
);
645 if (Attributes
!= NULL
) {
646 *Attributes
= RtPtrTrack
.CurrPtr
->Attributes
;
649 *DataSize
= TempDataSize
;
651 UpdateVariableInfo (VariableName
, VendorGuid
, RtPtrTrack
.Volatile
, TRUE
, FALSE
, FALSE
, TRUE
, &mVariableInfo
);
653 Status
= EFI_SUCCESS
;
656 *DataSize
= TempDataSize
;
657 Status
= EFI_BUFFER_TOO_SMALL
;
664 mVariableRuntimeCacheReadLock
= FALSE
;
670 Finds the given variable in a variable store in SMM.
672 Caution: This function may receive untrusted input.
673 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
675 @param[in] VariableName Name of Variable to be found.
676 @param[in] VendorGuid Variable vendor GUID.
677 @param[out] Attributes Attribute value of the variable found.
678 @param[in, out] DataSize Size of Data found. If size is less than the
679 data, this value contains the required size.
680 @param[out] Data Data pointer.
682 @retval EFI_SUCCESS Found the specified variable.
683 @retval EFI_INVALID_PARAMETER Invalid parameter.
684 @retval EFI_NOT_FOUND The specified variable could not be found.
689 IN CHAR16
*VariableName
,
690 IN EFI_GUID
*VendorGuid
,
691 OUT UINT32
*Attributes OPTIONAL
,
692 IN OUT UINTN
*DataSize
,
693 OUT VOID
*Data OPTIONAL
698 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
700 UINTN VariableNameSize
;
702 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
703 return EFI_INVALID_PARAMETER
;
706 TempDataSize
= *DataSize
;
707 VariableNameSize
= StrSize (VariableName
);
708 SmmVariableHeader
= NULL
;
711 // If VariableName exceeds SMM payload limit. Return failure
713 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
714 return EFI_INVALID_PARAMETER
;
718 // Init the communicate buffer. The buffer data size is:
719 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
721 if (TempDataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
) {
723 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
725 TempDataSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
;
727 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ TempDataSize
;
729 Status
= InitCommunicateBuffer ((VOID
**) &SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_VARIABLE
);
730 if (EFI_ERROR (Status
)) {
733 ASSERT (SmmVariableHeader
!= NULL
);
735 CopyGuid (&SmmVariableHeader
->Guid
, VendorGuid
);
736 SmmVariableHeader
->DataSize
= TempDataSize
;
737 SmmVariableHeader
->NameSize
= VariableNameSize
;
738 if (Attributes
== NULL
) {
739 SmmVariableHeader
->Attributes
= 0;
741 SmmVariableHeader
->Attributes
= *Attributes
;
743 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
748 Status
= SendCommunicateBuffer (PayloadSize
);
751 // Get data from SMM.
753 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
755 // SMM CommBuffer DataSize can be a trimed value
756 // Only update DataSize when needed
758 *DataSize
= SmmVariableHeader
->DataSize
;
760 if (Attributes
!= NULL
) {
761 *Attributes
= SmmVariableHeader
->Attributes
;
764 if (EFI_ERROR (Status
)) {
769 CopyMem (Data
, (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, SmmVariableHeader
->DataSize
);
771 Status
= EFI_INVALID_PARAMETER
;
779 This code finds variable in storage blocks (Volatile or Non-Volatile).
781 Caution: This function may receive untrusted input.
782 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
784 @param[in] VariableName Name of Variable to be found.
785 @param[in] VendorGuid Variable vendor GUID.
786 @param[out] Attributes Attribute value of the variable found.
787 @param[in, out] DataSize Size of Data found. If size is less than the
788 data, this value contains the required size.
789 @param[out] Data Data pointer.
791 @retval EFI_INVALID_PARAMETER Invalid parameter.
792 @retval EFI_SUCCESS Find the specified variable.
793 @retval EFI_NOT_FOUND Not found.
794 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
799 RuntimeServiceGetVariable (
800 IN CHAR16
*VariableName
,
801 IN EFI_GUID
*VendorGuid
,
802 OUT UINT32
*Attributes OPTIONAL
,
803 IN OUT UINTN
*DataSize
,
809 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
810 return EFI_INVALID_PARAMETER
;
812 if (VariableName
[0] == 0) {
813 return EFI_NOT_FOUND
;
816 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
817 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
818 Status
= FindVariableInRuntimeCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
820 Status
= FindVariableInSmm (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
822 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
828 Finds the next available variable in a runtime cache variable store.
830 @param[in, out] VariableNameSize Size of the variable name.
831 @param[in, out] VariableName Pointer to variable name.
832 @param[in, out] VendorGuid Variable Vendor Guid.
834 @retval EFI_INVALID_PARAMETER Invalid parameter.
835 @retval EFI_SUCCESS Find the specified variable.
836 @retval EFI_NOT_FOUND Not found.
837 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
841 GetNextVariableNameInRuntimeCache (
842 IN OUT UINTN
*VariableNameSize
,
843 IN OUT CHAR16
*VariableName
,
844 IN OUT EFI_GUID
*VendorGuid
849 VARIABLE_HEADER
*VariablePtr
;
850 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
852 Status
= EFI_NOT_FOUND
;
855 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
856 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
857 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
858 // cache read lock should always be free when entering this function.
860 ASSERT (!mVariableRuntimeCacheReadLock
);
862 CheckForRuntimeCacheSync ();
864 mVariableRuntimeCacheReadLock
= TRUE
;
865 if (!mVariableRuntimeCachePendingUpdate
) {
867 // 0: Volatile, 1: HOB, 2: Non-Volatile.
868 // The index and attributes mapping must be kept in this order as FindVariable
869 // makes use of this mapping to implement search algorithm.
871 VariableStoreHeader
[VariableStoreTypeVolatile
] = mVariableRuntimeVolatileCacheBuffer
;
872 VariableStoreHeader
[VariableStoreTypeHob
] = mVariableRuntimeHobCacheBuffer
;
873 VariableStoreHeader
[VariableStoreTypeNv
] = mVariableRuntimeNvCacheBuffer
;
875 Status
= VariableServiceGetNextVariableInternal (
882 if (!EFI_ERROR (Status
)) {
883 VarNameSize
= NameSizeOfVariable (VariablePtr
, mVariableAuthFormat
);
884 ASSERT (VarNameSize
!= 0);
885 if (VarNameSize
<= *VariableNameSize
) {
886 CopyMem (VariableName
, GetVariableNamePtr (VariablePtr
, mVariableAuthFormat
), VarNameSize
);
887 CopyMem (VendorGuid
, GetVendorGuidPtr (VariablePtr
, mVariableAuthFormat
), sizeof (EFI_GUID
));
888 Status
= EFI_SUCCESS
;
890 Status
= EFI_BUFFER_TOO_SMALL
;
893 *VariableNameSize
= VarNameSize
;
896 mVariableRuntimeCacheReadLock
= FALSE
;
902 Finds the next available variable in a SMM variable store.
904 @param[in, out] VariableNameSize Size of the variable name.
905 @param[in, out] VariableName Pointer to variable name.
906 @param[in, out] VendorGuid Variable Vendor Guid.
908 @retval EFI_INVALID_PARAMETER Invalid parameter.
909 @retval EFI_SUCCESS Find the specified variable.
910 @retval EFI_NOT_FOUND Not found.
911 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
915 GetNextVariableNameInSmm (
916 IN OUT UINTN
*VariableNameSize
,
917 IN OUT CHAR16
*VariableName
,
918 IN OUT EFI_GUID
*VendorGuid
923 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*SmmGetNextVariableName
;
924 UINTN OutVariableNameSize
;
925 UINTN InVariableNameSize
;
927 OutVariableNameSize
= *VariableNameSize
;
928 InVariableNameSize
= StrSize (VariableName
);
929 SmmGetNextVariableName
= NULL
;
932 // If input string exceeds SMM payload limit. Return failure
934 if (InVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
935 return EFI_INVALID_PARAMETER
;
939 // Init the communicate buffer. The buffer data size is:
940 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
942 if (OutVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
944 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
946 OutVariableNameSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
949 // Payload should be Guid + NameSize + MAX of Input & Output buffer
951 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + MAX (OutVariableNameSize
, InVariableNameSize
);
953 Status
= InitCommunicateBuffer ((VOID
**)&SmmGetNextVariableName
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
);
954 if (EFI_ERROR (Status
)) {
957 ASSERT (SmmGetNextVariableName
!= NULL
);
960 // SMM comm buffer->NameSize is buffer size for return string
962 SmmGetNextVariableName
->NameSize
= OutVariableNameSize
;
964 CopyGuid (&SmmGetNextVariableName
->Guid
, VendorGuid
);
968 CopyMem (SmmGetNextVariableName
->Name
, VariableName
, InVariableNameSize
);
969 if (OutVariableNameSize
> InVariableNameSize
) {
970 ZeroMem ((UINT8
*) SmmGetNextVariableName
->Name
+ InVariableNameSize
, OutVariableNameSize
- InVariableNameSize
);
976 Status
= SendCommunicateBuffer (PayloadSize
);
979 // Get data from SMM.
981 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
983 // SMM CommBuffer NameSize can be a trimed value
984 // Only update VariableNameSize when needed
986 *VariableNameSize
= SmmGetNextVariableName
->NameSize
;
988 if (EFI_ERROR (Status
)) {
992 CopyGuid (VendorGuid
, &SmmGetNextVariableName
->Guid
);
993 CopyMem (VariableName
, SmmGetNextVariableName
->Name
, SmmGetNextVariableName
->NameSize
);
1000 This code Finds the Next available variable.
1002 @param[in, out] VariableNameSize Size of the variable name.
1003 @param[in, out] VariableName Pointer to variable name.
1004 @param[in, out] VendorGuid Variable Vendor Guid.
1006 @retval EFI_INVALID_PARAMETER Invalid parameter.
1007 @retval EFI_SUCCESS Find the specified variable.
1008 @retval EFI_NOT_FOUND Not found.
1009 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
1014 RuntimeServiceGetNextVariableName (
1015 IN OUT UINTN
*VariableNameSize
,
1016 IN OUT CHAR16
*VariableName
,
1017 IN OUT EFI_GUID
*VendorGuid
1023 Status
= EFI_NOT_FOUND
;
1025 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
1026 return EFI_INVALID_PARAMETER
;
1030 // Calculate the possible maximum length of name string, including the Null terminator.
1032 MaxLen
= *VariableNameSize
/ sizeof (CHAR16
);
1033 if ((MaxLen
== 0) || (StrnLenS (VariableName
, MaxLen
) == MaxLen
)) {
1035 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
1036 // follow spec to return EFI_INVALID_PARAMETER.
1038 return EFI_INVALID_PARAMETER
;
1041 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1042 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
1043 Status
= GetNextVariableNameInRuntimeCache (VariableNameSize
, VariableName
, VendorGuid
);
1045 Status
= GetNextVariableNameInSmm (VariableNameSize
, VariableName
, VendorGuid
);
1047 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1053 This code sets variable in storage blocks (Volatile or Non-Volatile).
1055 Caution: This function may receive untrusted input.
1056 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
1058 @param[in] VariableName Name of Variable to be found.
1059 @param[in] VendorGuid Variable vendor GUID.
1060 @param[in] Attributes Attribute value of the variable found
1061 @param[in] DataSize Size of Data found. If size is less than the
1062 data, this value contains the required size.
1063 @param[in] Data Data pointer.
1065 @retval EFI_INVALID_PARAMETER Invalid parameter.
1066 @retval EFI_SUCCESS Set successfully.
1067 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
1068 @retval EFI_NOT_FOUND Not found.
1069 @retval EFI_WRITE_PROTECTED Variable is read-only.
1074 RuntimeServiceSetVariable (
1075 IN CHAR16
*VariableName
,
1076 IN EFI_GUID
*VendorGuid
,
1077 IN UINT32 Attributes
,
1084 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
1085 UINTN VariableNameSize
;
1088 // Check input parameters.
1090 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
1091 return EFI_INVALID_PARAMETER
;
1094 if (DataSize
!= 0 && Data
== NULL
) {
1095 return EFI_INVALID_PARAMETER
;
1098 VariableNameSize
= StrSize (VariableName
);
1099 SmmVariableHeader
= NULL
;
1102 // If VariableName or DataSize exceeds SMM payload limit. Return failure
1104 if ((VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
1105 (DataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
)){
1106 return EFI_INVALID_PARAMETER
;
1109 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
1112 // Init the communicate buffer. The buffer data size is:
1113 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
1115 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ DataSize
;
1116 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_SET_VARIABLE
);
1117 if (EFI_ERROR (Status
)) {
1120 ASSERT (SmmVariableHeader
!= NULL
);
1122 CopyGuid ((EFI_GUID
*) &SmmVariableHeader
->Guid
, VendorGuid
);
1123 SmmVariableHeader
->DataSize
= DataSize
;
1124 SmmVariableHeader
->NameSize
= VariableNameSize
;
1125 SmmVariableHeader
->Attributes
= Attributes
;
1126 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
1127 CopyMem ((UINT8
*) SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, Data
, DataSize
);
1130 // Send data to SMM.
1132 Status
= SendCommunicateBuffer (PayloadSize
);
1135 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1137 if (!EfiAtRuntime ()) {
1138 if (!EFI_ERROR (Status
)) {
1150 This code returns information about the EFI variables.
1152 @param[in] Attributes Attributes bitmask to specify the type of variables
1153 on which to return information.
1154 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1155 for the EFI variables associated with the attributes specified.
1156 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1157 for EFI variables associated with the attributes specified.
1158 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1159 associated with the attributes specified.
1161 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
1162 @retval EFI_SUCCESS Query successfully.
1163 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
1168 RuntimeServiceQueryVariableInfo (
1169 IN UINT32 Attributes
,
1170 OUT UINT64
*MaximumVariableStorageSize
,
1171 OUT UINT64
*RemainingVariableStorageSize
,
1172 OUT UINT64
*MaximumVariableSize
1177 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*SmmQueryVariableInfo
;
1179 SmmQueryVariableInfo
= NULL
;
1181 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
1182 return EFI_INVALID_PARAMETER
;
1185 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
1188 // Init the communicate buffer. The buffer data size is:
1189 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
1191 PayloadSize
= sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
1192 Status
= InitCommunicateBuffer ((VOID
**)&SmmQueryVariableInfo
, PayloadSize
, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
);
1193 if (EFI_ERROR (Status
)) {
1196 ASSERT (SmmQueryVariableInfo
!= NULL
);
1198 SmmQueryVariableInfo
->Attributes
= Attributes
;
1201 // Send data to SMM.
1203 Status
= SendCommunicateBuffer (PayloadSize
);
1204 if (EFI_ERROR (Status
)) {
1209 // Get data from SMM.
1211 *MaximumVariableSize
= SmmQueryVariableInfo
->MaximumVariableSize
;
1212 *MaximumVariableStorageSize
= SmmQueryVariableInfo
->MaximumVariableStorageSize
;
1213 *RemainingVariableStorageSize
= SmmQueryVariableInfo
->RemainingVariableStorageSize
;
1216 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1222 Exit Boot Services Event notification handler.
1224 Notify SMM variable driver about the event.
1226 @param[in] Event Event whose notification function is being invoked.
1227 @param[in] Context Pointer to the notification function's context.
1232 OnExitBootServices (
1238 // Init the communicate buffer. The buffer data size is:
1239 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
1241 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
);
1244 // Send data to SMM.
1246 SendCommunicateBuffer (0);
1251 On Ready To Boot Services Event notification handler.
1253 Notify SMM variable driver about the event.
1255 @param[in] Event Event whose notification function is being invoked
1256 @param[in] Context Pointer to the notification function's context
1267 // Init the communicate buffer. The buffer data size is:
1268 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
1270 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT
);
1273 // Send data to SMM.
1275 SendCommunicateBuffer (0);
1278 // Install the system configuration table for variable info data captured
1280 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
) && FeaturePcdGet (PcdVariableCollectStatistics
)) {
1281 if (mVariableAuthFormat
) {
1282 gBS
->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid
, mVariableInfo
);
1284 gBS
->InstallConfigurationTable (&gEfiVariableGuid
, mVariableInfo
);
1288 gBS
->CloseEvent (Event
);
1293 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
1295 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1296 It convers pointer to new virtual address.
1298 @param[in] Event Event whose notification function is being invoked.
1299 @param[in] Context Pointer to the notification function's context.
1304 VariableAddressChangeEvent (
1309 EfiConvertPointer (0x0, (VOID
**) &mVariableBuffer
);
1310 EfiConvertPointer (0x0, (VOID
**) &mSmmCommunication
);
1311 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**) &mVariableRuntimeHobCacheBuffer
);
1312 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**) &mVariableRuntimeNvCacheBuffer
);
1313 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**) &mVariableRuntimeVolatileCacheBuffer
);
1317 This code gets variable payload size.
1319 @param[out] VariablePayloadSize Output pointer to variable payload size.
1321 @retval EFI_SUCCESS Get successfully.
1322 @retval Others Get unsuccessfully.
1327 GetVariablePayloadSize (
1328 OUT UINTN
*VariablePayloadSize
1332 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*SmmGetPayloadSize
;
1333 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1334 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1338 SmmGetPayloadSize
= NULL
;
1341 if(VariablePayloadSize
== NULL
) {
1342 return EFI_INVALID_PARAMETER
;
1345 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
1348 // Init the communicate buffer. The buffer data size is:
1349 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
1351 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
1352 CommBuffer
= AllocateZeroPool (CommSize
);
1353 if (CommBuffer
== NULL
) {
1354 Status
= EFI_OUT_OF_RESOURCES
;
1358 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) CommBuffer
;
1359 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1360 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
1362 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
1363 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE
;
1364 SmmGetPayloadSize
= (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*) SmmVariableFunctionHeader
->Data
;
1367 // Send data to SMM.
1369 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, CommBuffer
, &CommSize
);
1370 ASSERT_EFI_ERROR (Status
);
1372 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1373 if (EFI_ERROR (Status
)) {
1378 // Get data from SMM.
1380 *VariablePayloadSize
= SmmGetPayloadSize
->VariablePayloadSize
;
1383 if (CommBuffer
!= NULL
) {
1384 FreePool (CommBuffer
);
1386 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1391 This code gets information needed from SMM for runtime cache initialization.
1393 @param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes.
1394 @param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes.
1395 @param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes.
1396 @param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used.
1398 @retval EFI_SUCCESS Retrieved the size successfully.
1399 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
1400 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
1401 @retval Others Could not retrieve the size successfully.
1405 GetRuntimeCacheInfo (
1406 OUT UINTN
*TotalHobStorageSize
,
1407 OUT UINTN
*TotalNvStorageSize
,
1408 OUT UINTN
*TotalVolatileStorageSize
,
1409 OUT BOOLEAN
*AuthenticatedVariableUsage
1413 SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
*SmmGetRuntimeCacheInfo
;
1414 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1415 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1419 SmmGetRuntimeCacheInfo
= NULL
;
1420 CommBuffer
= mVariableBuffer
;
1422 if (TotalHobStorageSize
== NULL
|| TotalNvStorageSize
== NULL
|| TotalVolatileStorageSize
== NULL
|| AuthenticatedVariableUsage
== NULL
) {
1423 return EFI_INVALID_PARAMETER
;
1426 if (CommBuffer
== NULL
) {
1427 return EFI_OUT_OF_RESOURCES
;
1430 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1432 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
);
1433 ZeroMem (CommBuffer
, CommSize
);
1435 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) CommBuffer
;
1436 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1437 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
);
1439 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
1440 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO
;
1441 SmmGetRuntimeCacheInfo
= (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
*) SmmVariableFunctionHeader
->Data
;
1444 // Send data to SMM.
1446 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, CommBuffer
, &CommSize
);
1447 ASSERT_EFI_ERROR (Status
);
1448 if (CommSize
<= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
1449 Status
= EFI_BAD_BUFFER_SIZE
;
1453 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1454 if (EFI_ERROR (Status
)) {
1459 // Get data from SMM.
1461 *TotalHobStorageSize
= SmmGetRuntimeCacheInfo
->TotalHobStorageSize
;
1462 *TotalNvStorageSize
= SmmGetRuntimeCacheInfo
->TotalNvStorageSize
;
1463 *TotalVolatileStorageSize
= SmmGetRuntimeCacheInfo
->TotalVolatileStorageSize
;
1464 *AuthenticatedVariableUsage
= SmmGetRuntimeCacheInfo
->AuthenticatedVariableUsage
;
1467 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1472 Sends the runtime variable cache context information to SMM.
1474 @retval EFI_SUCCESS Retrieved the size successfully.
1475 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
1476 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
1477 @retval Others Could not retrieve the size successfully.;
1481 SendRuntimeVariableCacheContextToSmm (
1486 SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
*SmmRuntimeVarCacheContext
;
1487 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1488 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1492 SmmRuntimeVarCacheContext
= NULL
;
1493 CommBuffer
= mVariableBuffer
;
1495 if (CommBuffer
== NULL
) {
1496 return EFI_OUT_OF_RESOURCES
;
1499 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1502 // Init the communicate buffer. The buffer data size is:
1503 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
1505 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
);
1506 ZeroMem (CommBuffer
, CommSize
);
1508 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) CommBuffer
;
1509 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1510 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
);
1512 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
1513 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT
;
1514 SmmRuntimeVarCacheContext
= (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
*) SmmVariableFunctionHeader
->Data
;
1516 SmmRuntimeVarCacheContext
->RuntimeHobCache
= mVariableRuntimeHobCacheBuffer
;
1517 SmmRuntimeVarCacheContext
->RuntimeVolatileCache
= mVariableRuntimeVolatileCacheBuffer
;
1518 SmmRuntimeVarCacheContext
->RuntimeNvCache
= mVariableRuntimeNvCacheBuffer
;
1519 SmmRuntimeVarCacheContext
->PendingUpdate
= &mVariableRuntimeCachePendingUpdate
;
1520 SmmRuntimeVarCacheContext
->ReadLock
= &mVariableRuntimeCacheReadLock
;
1521 SmmRuntimeVarCacheContext
->HobFlushComplete
= &mHobFlushComplete
;
1524 // Send data to SMM.
1526 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, CommBuffer
, &CommSize
);
1527 ASSERT_EFI_ERROR (Status
);
1528 if (CommSize
<= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
1529 Status
= EFI_BAD_BUFFER_SIZE
;
1533 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1534 if (EFI_ERROR (Status
)) {
1539 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1544 Initialize variable service and install Variable Architectural protocol.
1546 @param[in] Event Event whose notification function is being invoked.
1547 @param[in] Context Pointer to the notification function's context.
1559 Status
= gBS
->LocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**) &mSmmVariable
);
1560 if (EFI_ERROR (Status
)) {
1564 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &mSmmCommunication
);
1565 ASSERT_EFI_ERROR (Status
);
1568 // Allocate memory for variable communicate buffer.
1570 Status
= GetVariablePayloadSize (&mVariableBufferPayloadSize
);
1571 ASSERT_EFI_ERROR (Status
);
1572 mVariableBufferSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ mVariableBufferPayloadSize
;
1573 mVariableBuffer
= AllocateRuntimePool (mVariableBufferSize
);
1574 ASSERT (mVariableBuffer
!= NULL
);
1577 // Save the buffer physical address used for SMM conmunication.
1579 mVariableBufferPhysical
= mVariableBuffer
;
1581 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
1582 DEBUG ((DEBUG_INFO
, "Variable driver runtime cache is enabled.\n"));
1584 // Allocate runtime variable cache memory buffers.
1586 Status
= GetRuntimeCacheInfo (
1587 &mVariableRuntimeHobCacheBufferSize
,
1588 &mVariableRuntimeNvCacheBufferSize
,
1589 &mVariableRuntimeVolatileCacheBufferSize
,
1590 &mVariableAuthFormat
1592 if (!EFI_ERROR (Status
)) {
1593 Status
= InitVariableCache (&mVariableRuntimeHobCacheBuffer
, &mVariableRuntimeHobCacheBufferSize
);
1594 if (!EFI_ERROR (Status
)) {
1595 Status
= InitVariableCache (&mVariableRuntimeNvCacheBuffer
, &mVariableRuntimeNvCacheBufferSize
);
1596 if (!EFI_ERROR (Status
)) {
1597 Status
= InitVariableCache (&mVariableRuntimeVolatileCacheBuffer
, &mVariableRuntimeVolatileCacheBufferSize
);
1598 if (!EFI_ERROR (Status
)) {
1599 Status
= SendRuntimeVariableCacheContextToSmm ();
1600 if (!EFI_ERROR (Status
)) {
1601 SyncRuntimeCache ();
1606 if (EFI_ERROR (Status
)) {
1607 mVariableRuntimeHobCacheBuffer
= NULL
;
1608 mVariableRuntimeNvCacheBuffer
= NULL
;
1609 mVariableRuntimeVolatileCacheBuffer
= NULL
;
1612 ASSERT_EFI_ERROR (Status
);
1614 DEBUG ((DEBUG_INFO
, "Variable driver runtime cache is disabled.\n"));
1617 gRT
->GetVariable
= RuntimeServiceGetVariable
;
1618 gRT
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
1619 gRT
->SetVariable
= RuntimeServiceSetVariable
;
1620 gRT
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
1623 // Install the Variable Architectural Protocol on a new handle.
1625 Status
= gBS
->InstallProtocolInterface (
1627 &gEfiVariableArchProtocolGuid
,
1628 EFI_NATIVE_INTERFACE
,
1631 ASSERT_EFI_ERROR (Status
);
1633 mVariableLock
.RequestToLock
= VariableLockRequestToLock
;
1634 Status
= gBS
->InstallMultipleProtocolInterfaces (
1636 &gEdkiiVariableLockProtocolGuid
,
1640 ASSERT_EFI_ERROR (Status
);
1642 mVarCheck
.RegisterSetVariableCheckHandler
= VarCheckRegisterSetVariableCheckHandler
;
1643 mVarCheck
.VariablePropertySet
= VarCheckVariablePropertySet
;
1644 mVarCheck
.VariablePropertyGet
= VarCheckVariablePropertyGet
;
1645 Status
= gBS
->InstallMultipleProtocolInterfaces (
1647 &gEdkiiVarCheckProtocolGuid
,
1651 ASSERT_EFI_ERROR (Status
);
1653 gBS
->CloseEvent (Event
);
1658 SMM Non-Volatile variable write service is ready notify event handler.
1660 @param[in] Event Event whose notification function is being invoked.
1661 @param[in] Context Pointer to the notification function's context.
1666 SmmVariableWriteReady (
1675 // Check whether the protocol is installed or not.
1677 Status
= gBS
->LocateProtocol (&gSmmVariableWriteGuid
, NULL
, (VOID
**) &ProtocolOps
);
1678 if (EFI_ERROR (Status
)) {
1683 // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
1684 // Secure Boot Policy Variable change. Record their initial value.
1686 RecordSecureBootPolicyVarData();
1688 Status
= gBS
->InstallProtocolInterface (
1690 &gEfiVariableWriteArchProtocolGuid
,
1691 EFI_NATIVE_INTERFACE
,
1694 ASSERT_EFI_ERROR (Status
);
1696 gBS
->CloseEvent (Event
);
1701 Variable Driver main entry point. The Variable driver places the 4 EFI
1702 runtime services in the EFI System Table and installs arch protocols
1703 for variable read and write services being available. It also registers
1704 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1706 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1707 @param[in] SystemTable A pointer to the EFI System Table.
1709 @retval EFI_SUCCESS Variable service successfully initialized.
1714 VariableSmmRuntimeInitialize (
1715 IN EFI_HANDLE ImageHandle
,
1716 IN EFI_SYSTEM_TABLE
*SystemTable
1719 VOID
*SmmVariableRegistration
;
1720 VOID
*SmmVariableWriteRegistration
;
1721 EFI_EVENT OnReadyToBootEvent
;
1722 EFI_EVENT ExitBootServiceEvent
;
1723 EFI_EVENT LegacyBootEvent
;
1725 EfiInitializeLock (&mVariableServicesLock
, TPL_NOTIFY
);
1728 // Smm variable service is ready
1730 EfiCreateProtocolNotifyEvent (
1731 &gEfiSmmVariableProtocolGuid
,
1735 &SmmVariableRegistration
1739 // Smm Non-Volatile variable write service is ready
1741 EfiCreateProtocolNotifyEvent (
1742 &gSmmVariableWriteGuid
,
1744 SmmVariableWriteReady
,
1746 &SmmVariableWriteRegistration
1750 // Register the event to reclaim variable for OS usage.
1752 EfiCreateEventReadyToBootEx (
1760 // Register the event to inform SMM variable that it is at runtime.
1762 gBS
->CreateEventEx (
1767 &gEfiEventExitBootServicesGuid
,
1768 &ExitBootServiceEvent
1772 // Register the event to inform SMM variable that it is at runtime for legacy boot.
1773 // Reuse OnExitBootServices() here.
1775 EfiCreateEventLegacyBootEx(
1783 // Register the event to convert the pointer for runtime.
1785 gBS
->CreateEventEx (
1788 VariableAddressChangeEvent
,
1790 &gEfiEventVirtualAddressChangeGuid
,
1791 &mVirtualAddressChangeEvent