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 Copyright (c) Microsoft Corporation.<BR>
18 SPDX-License-Identifier: BSD-2-Clause-Patent
22 #include <Protocol/VariableWrite.h>
23 #include <Protocol/Variable.h>
24 #include <Protocol/MmCommunication2.h>
25 #include <Protocol/SmmVariable.h>
26 #include <Protocol/VariableLock.h>
27 #include <Protocol/VarCheck.h>
29 #include <Library/UefiBootServicesTableLib.h>
30 #include <Library/UefiRuntimeServicesTableLib.h>
31 #include <Library/MemoryAllocationLib.h>
32 #include <Library/UefiDriverEntryPoint.h>
33 #include <Library/UefiRuntimeLib.h>
34 #include <Library/BaseMemoryLib.h>
35 #include <Library/DebugLib.h>
36 #include <Library/UefiLib.h>
37 #include <Library/BaseLib.h>
38 #include <Library/MmUnblockMemoryLib.h>
40 #include <Guid/EventGroup.h>
41 #include <Guid/SmmVariableCommon.h>
43 #include "PrivilegePolymorphic.h"
44 #include "VariableParsing.h"
46 EFI_HANDLE mHandle
= NULL
;
47 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
= NULL
;
48 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
49 EFI_MM_COMMUNICATION2_PROTOCOL
*mMmCommunication2
= NULL
;
50 UINT8
*mVariableBuffer
= NULL
;
51 UINT8
*mVariableBufferPhysical
= NULL
;
52 VARIABLE_INFO_ENTRY
*mVariableInfo
= NULL
;
53 VARIABLE_STORE_HEADER
*mVariableRuntimeHobCacheBuffer
= NULL
;
54 VARIABLE_STORE_HEADER
*mVariableRuntimeNvCacheBuffer
= NULL
;
55 VARIABLE_STORE_HEADER
*mVariableRuntimeVolatileCacheBuffer
= NULL
;
56 UINTN mVariableBufferSize
;
57 UINTN mVariableRuntimeHobCacheBufferSize
;
58 UINTN mVariableRuntimeNvCacheBufferSize
;
59 UINTN mVariableRuntimeVolatileCacheBufferSize
;
60 UINTN mVariableBufferPayloadSize
;
61 BOOLEAN mVariableRuntimeCachePendingUpdate
;
62 BOOLEAN mVariableRuntimeCacheReadLock
;
63 BOOLEAN mVariableAuthFormat
;
64 BOOLEAN mHobFlushComplete
;
65 EFI_LOCK mVariableServicesLock
;
66 EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock
;
67 EDKII_VAR_CHECK_PROTOCOL mVarCheck
;
70 The logic to initialize the VariablePolicy engine is in its own file.
75 VariablePolicySmmDxeMain (
76 IN EFI_HANDLE ImageHandle
,
77 IN EFI_SYSTEM_TABLE
*SystemTable
81 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
82 Record their initial State when variable write service is ready.
87 RecordSecureBootPolicyVarData (
92 Acquires lock only at boot time. Simply returns at runtime.
94 This is a temperary function that will be removed when
95 EfiAcquireLock() in UefiLib can handle the call in UEFI
96 Runtimer driver in RT phase.
97 It calls EfiAcquireLock() at boot time, and simply returns
100 @param Lock A pointer to the lock to acquire.
104 AcquireLockOnlyAtBootTime (
108 if (!EfiAtRuntime ()) {
109 EfiAcquireLock (Lock
);
114 Releases lock only at boot time. Simply returns at runtime.
116 This is a temperary function which will be removed when
117 EfiReleaseLock() in UefiLib can handle the call in UEFI
118 Runtimer driver in RT phase.
119 It calls EfiReleaseLock() at boot time and simply returns
122 @param Lock A pointer to the lock to release.
126 ReleaseLockOnlyAtBootTime (
130 if (!EfiAtRuntime ()) {
131 EfiReleaseLock (Lock
);
136 Return TRUE if ExitBootServices () has been called.
138 @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.
145 return EfiAtRuntime ();
149 Initialize the variable cache buffer as an empty variable store.
151 @param[out] VariableCacheBuffer A pointer to pointer of a cache variable store.
152 @param[in,out] TotalVariableCacheSize On input, the minimum size needed for the UEFI variable store cache
153 buffer that is allocated. On output, the actual size of the buffer allocated.
154 If TotalVariableCacheSize is zero, a buffer will not be allocated and the
155 function will return with EFI_SUCCESS.
157 @retval EFI_SUCCESS The variable cache was allocated and initialized successfully.
158 @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid variable store size was specified.
159 @retval EFI_OUT_OF_RESOURCES Insufficient resources are available to allocate the variable store cache buffer.
164 OUT VARIABLE_STORE_HEADER
**VariableCacheBuffer
,
165 IN OUT UINTN
*TotalVariableCacheSize
168 VARIABLE_STORE_HEADER
*VariableCacheStorePtr
;
171 if (TotalVariableCacheSize
== NULL
) {
172 return EFI_INVALID_PARAMETER
;
175 if (*TotalVariableCacheSize
== 0) {
179 if ((VariableCacheBuffer
== NULL
) || (*TotalVariableCacheSize
< sizeof (VARIABLE_STORE_HEADER
))) {
180 return EFI_INVALID_PARAMETER
;
183 *TotalVariableCacheSize
= ALIGN_VALUE (*TotalVariableCacheSize
, sizeof (UINT32
));
186 // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)
188 *VariableCacheBuffer
= (VARIABLE_STORE_HEADER
*)AllocateRuntimePages (
189 EFI_SIZE_TO_PAGES (*TotalVariableCacheSize
)
191 if (*VariableCacheBuffer
== NULL
) {
192 return EFI_OUT_OF_RESOURCES
;
196 // Request to unblock the newly allocated cache region to be accessible from inside MM
198 Status
= MmUnblockMemoryRequest (
199 (EFI_PHYSICAL_ADDRESS
)(UINTN
)*VariableCacheBuffer
,
200 EFI_SIZE_TO_PAGES (*TotalVariableCacheSize
)
202 if ((Status
!= EFI_UNSUPPORTED
) && EFI_ERROR (Status
)) {
206 VariableCacheStorePtr
= *VariableCacheBuffer
;
207 SetMem32 ((VOID
*)VariableCacheStorePtr
, *TotalVariableCacheSize
, (UINT32
)0xFFFFFFFF);
209 ZeroMem ((VOID
*)VariableCacheStorePtr
, sizeof (VARIABLE_STORE_HEADER
));
210 VariableCacheStorePtr
->Size
= (UINT32
)*TotalVariableCacheSize
;
211 VariableCacheStorePtr
->Format
= VARIABLE_STORE_FORMATTED
;
212 VariableCacheStorePtr
->State
= VARIABLE_STORE_HEALTHY
;
218 Initialize the communicate buffer using DataSize and Function.
220 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
223 Caution: This function may receive untrusted input.
224 The data size external input, so this function will validate it carefully to avoid buffer overflow.
226 @param[out] DataPtr Points to the data in the communicate buffer.
227 @param[in] DataSize The data size to send to SMM.
228 @param[in] Function The function number to initialize the communicate header.
230 @retval EFI_INVALID_PARAMETER The data size is too big.
231 @retval EFI_SUCCESS Find the specified variable.
235 InitCommunicateBuffer (
236 OUT VOID
**DataPtr OPTIONAL
,
241 EFI_MM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
242 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
244 if (DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
> mVariableBufferSize
) {
245 return EFI_INVALID_PARAMETER
;
248 SmmCommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)mVariableBuffer
;
249 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
250 SmmCommunicateHeader
->MessageLength
= DataSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
252 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
253 SmmVariableFunctionHeader
->Function
= Function
;
254 if (DataPtr
!= NULL
) {
255 *DataPtr
= SmmVariableFunctionHeader
->Data
;
262 Send the data in communicate buffer to SMM.
264 @param[in] DataSize This size of the function header and the data.
266 @retval EFI_SUCCESS Success is returned from the functin in SMM.
267 @retval Others Failure is returned from the function in SMM.
271 SendCommunicateBuffer (
277 EFI_MM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
278 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
280 CommSize
= DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
281 Status
= mMmCommunication2
->Communicate (
283 mVariableBufferPhysical
,
287 ASSERT_EFI_ERROR (Status
);
289 SmmCommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)mVariableBuffer
;
290 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
291 return SmmVariableFunctionHeader
->ReturnStatus
;
295 Mark a variable that will become read-only after leaving the DXE phase of execution.
297 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
298 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
299 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
301 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
302 as pending to be read-only.
303 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
304 Or VariableName is an empty string.
305 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
306 already been signaled.
307 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
311 VariableLockRequestToLock (
312 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
313 IN CHAR16
*VariableName
,
314 IN EFI_GUID
*VendorGuid
318 UINTN VariableNameSize
;
320 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
322 if ((VariableName
== NULL
) || (VariableName
[0] == 0) || (VendorGuid
== NULL
)) {
323 return EFI_INVALID_PARAMETER
;
326 VariableNameSize
= StrSize (VariableName
);
327 VariableToLock
= NULL
;
330 // If VariableName exceeds SMM payload limit. Return failure
332 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
)) {
333 return EFI_INVALID_PARAMETER
;
336 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
339 // Init the communicate buffer. The buffer data size is:
340 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
342 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
) + VariableNameSize
;
343 Status
= InitCommunicateBuffer ((VOID
**)&VariableToLock
, PayloadSize
, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
);
344 if (EFI_ERROR (Status
)) {
348 ASSERT (VariableToLock
!= NULL
);
350 CopyGuid (&VariableToLock
->Guid
, VendorGuid
);
351 VariableToLock
->NameSize
= VariableNameSize
;
352 CopyMem (VariableToLock
->Name
, VariableName
, VariableToLock
->NameSize
);
357 Status
= SendCommunicateBuffer (PayloadSize
);
360 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
365 Register SetVariable check handler.
367 @param[in] Handler Pointer to check handler.
369 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
370 @retval EFI_INVALID_PARAMETER Handler is NULL.
371 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
372 already been signaled.
373 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
374 @retval EFI_UNSUPPORTED This interface is not implemented.
375 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
380 VarCheckRegisterSetVariableCheckHandler (
381 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
384 return EFI_UNSUPPORTED
;
388 Variable property set.
390 @param[in] Name Pointer to the variable name.
391 @param[in] Guid Pointer to the vendor GUID.
392 @param[in] VariableProperty Pointer to the input variable property.
394 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
395 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
396 or the fields of VariableProperty are not valid.
397 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
398 already been signaled.
399 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
404 VarCheckVariablePropertySet (
407 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
411 UINTN VariableNameSize
;
413 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
415 if ((Name
== NULL
) || (Name
[0] == 0) || (Guid
== NULL
)) {
416 return EFI_INVALID_PARAMETER
;
419 if (VariableProperty
== NULL
) {
420 return EFI_INVALID_PARAMETER
;
423 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
424 return EFI_INVALID_PARAMETER
;
427 VariableNameSize
= StrSize (Name
);
428 CommVariableProperty
= NULL
;
431 // If VariableName exceeds SMM payload limit. Return failure
433 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
434 return EFI_INVALID_PARAMETER
;
437 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
440 // Init the communicate buffer. The buffer data size is:
441 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
443 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
444 Status
= InitCommunicateBuffer ((VOID
**)&CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
);
445 if (EFI_ERROR (Status
)) {
449 ASSERT (CommVariableProperty
!= NULL
);
451 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
452 CopyMem (&CommVariableProperty
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
453 CommVariableProperty
->NameSize
= VariableNameSize
;
454 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
459 Status
= SendCommunicateBuffer (PayloadSize
);
462 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
467 Variable property get.
469 @param[in] Name Pointer to the variable name.
470 @param[in] Guid Pointer to the vendor GUID.
471 @param[out] VariableProperty Pointer to the output variable property.
473 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
474 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
475 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
480 VarCheckVariablePropertyGet (
483 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
487 UINTN VariableNameSize
;
489 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
491 if ((Name
== NULL
) || (Name
[0] == 0) || (Guid
== NULL
)) {
492 return EFI_INVALID_PARAMETER
;
495 if (VariableProperty
== NULL
) {
496 return EFI_INVALID_PARAMETER
;
499 VariableNameSize
= StrSize (Name
);
500 CommVariableProperty
= NULL
;
503 // If VariableName exceeds SMM payload limit. Return failure
505 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
506 return EFI_INVALID_PARAMETER
;
509 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
512 // Init the communicate buffer. The buffer data size is:
513 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
515 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
516 Status
= InitCommunicateBuffer ((VOID
**)&CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
);
517 if (EFI_ERROR (Status
)) {
521 ASSERT (CommVariableProperty
!= NULL
);
523 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
524 CommVariableProperty
->NameSize
= VariableNameSize
;
525 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
530 Status
= SendCommunicateBuffer (PayloadSize
);
531 if (Status
== EFI_SUCCESS
) {
532 CopyMem (VariableProperty
, &CommVariableProperty
->VariableProperty
, sizeof (*VariableProperty
));
536 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
541 Signals SMM to synchronize any pending variable updates with the runtime cache(s).
550 // Init the communicate buffer. The buffer data size is:
551 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
553 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE
);
558 SendCommunicateBuffer (0);
562 Check whether a SMI must be triggered to retrieve pending cache updates.
564 If the variable HOB was finished being flushed since the last check for a runtime cache update, this function
565 will prevent the HOB cache from being used for future runtime cache hits.
569 CheckForRuntimeCacheSync (
573 if (mVariableRuntimeCachePendingUpdate
) {
577 ASSERT (!mVariableRuntimeCachePendingUpdate
);
580 // The HOB variable data may have finished being flushed in the runtime cache sync update
582 if (mHobFlushComplete
&& (mVariableRuntimeHobCacheBuffer
!= NULL
)) {
583 if (!EfiAtRuntime ()) {
584 FreePages (mVariableRuntimeHobCacheBuffer
, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize
));
587 mVariableRuntimeHobCacheBuffer
= NULL
;
592 Finds the given variable in a runtime cache variable store.
594 Caution: This function may receive untrusted input.
595 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
597 @param[in] VariableName Name of Variable to be found.
598 @param[in] VendorGuid Variable vendor GUID.
599 @param[out] Attributes Attribute value of the variable found.
600 @param[in, out] DataSize Size of Data found. If size is less than the
601 data, this value contains the required size.
602 @param[out] Data Data pointer.
604 @retval EFI_SUCCESS Found the specified variable.
605 @retval EFI_INVALID_PARAMETER Invalid parameter.
606 @retval EFI_NOT_FOUND The specified variable could not be found.
610 FindVariableInRuntimeCache (
611 IN CHAR16
*VariableName
,
612 IN EFI_GUID
*VendorGuid
,
613 OUT UINT32
*Attributes OPTIONAL
,
614 IN OUT UINTN
*DataSize
,
615 OUT VOID
*Data OPTIONAL
620 VARIABLE_POINTER_TRACK RtPtrTrack
;
621 VARIABLE_STORE_TYPE StoreType
;
622 VARIABLE_STORE_HEADER
*VariableStoreList
[VariableStoreTypeMax
];
624 Status
= EFI_NOT_FOUND
;
626 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (DataSize
== NULL
)) {
627 return EFI_INVALID_PARAMETER
;
630 ZeroMem (&RtPtrTrack
, sizeof (RtPtrTrack
));
633 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
634 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
635 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
636 // cache read lock should always be free when entering this function.
638 ASSERT (!mVariableRuntimeCacheReadLock
);
640 mVariableRuntimeCacheReadLock
= TRUE
;
641 CheckForRuntimeCacheSync ();
643 if (!mVariableRuntimeCachePendingUpdate
) {
645 // 0: Volatile, 1: HOB, 2: Non-Volatile.
646 // The index and attributes mapping must be kept in this order as FindVariable
647 // makes use of this mapping to implement search algorithm.
649 VariableStoreList
[VariableStoreTypeVolatile
] = mVariableRuntimeVolatileCacheBuffer
;
650 VariableStoreList
[VariableStoreTypeHob
] = mVariableRuntimeHobCacheBuffer
;
651 VariableStoreList
[VariableStoreTypeNv
] = mVariableRuntimeNvCacheBuffer
;
653 for (StoreType
= (VARIABLE_STORE_TYPE
)0; StoreType
< VariableStoreTypeMax
; StoreType
++) {
654 if (VariableStoreList
[StoreType
] == NULL
) {
658 RtPtrTrack
.StartPtr
= GetStartPointer (VariableStoreList
[StoreType
]);
659 RtPtrTrack
.EndPtr
= GetEndPointer (VariableStoreList
[StoreType
]);
660 RtPtrTrack
.Volatile
= (BOOLEAN
)(StoreType
== VariableStoreTypeVolatile
);
662 Status
= FindVariableEx (VariableName
, VendorGuid
, FALSE
, &RtPtrTrack
, mVariableAuthFormat
);
663 if (!EFI_ERROR (Status
)) {
668 if (!EFI_ERROR (Status
)) {
672 TempDataSize
= DataSizeOfVariable (RtPtrTrack
.CurrPtr
, mVariableAuthFormat
);
673 ASSERT (TempDataSize
!= 0);
675 if (*DataSize
>= TempDataSize
) {
677 Status
= EFI_INVALID_PARAMETER
;
681 CopyMem (Data
, GetVariableDataPtr (RtPtrTrack
.CurrPtr
, mVariableAuthFormat
), TempDataSize
);
682 *DataSize
= TempDataSize
;
684 UpdateVariableInfo (VariableName
, VendorGuid
, RtPtrTrack
.Volatile
, TRUE
, FALSE
, FALSE
, TRUE
, &mVariableInfo
);
686 Status
= EFI_SUCCESS
;
689 *DataSize
= TempDataSize
;
690 Status
= EFI_BUFFER_TOO_SMALL
;
697 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_BUFFER_TOO_SMALL
)) {
698 if ((Attributes
!= NULL
) && (RtPtrTrack
.CurrPtr
!= NULL
)) {
699 *Attributes
= RtPtrTrack
.CurrPtr
->Attributes
;
703 mVariableRuntimeCacheReadLock
= FALSE
;
709 Finds the given variable in a variable store in SMM.
711 Caution: This function may receive untrusted input.
712 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
714 @param[in] VariableName Name of Variable to be found.
715 @param[in] VendorGuid Variable vendor GUID.
716 @param[out] Attributes Attribute value of the variable found.
717 @param[in, out] DataSize Size of Data found. If size is less than the
718 data, this value contains the required size.
719 @param[out] Data Data pointer.
721 @retval EFI_SUCCESS Found the specified variable.
722 @retval EFI_INVALID_PARAMETER Invalid parameter.
723 @retval EFI_NOT_FOUND The specified variable could not be found.
728 IN CHAR16
*VariableName
,
729 IN EFI_GUID
*VendorGuid
,
730 OUT UINT32
*Attributes OPTIONAL
,
731 IN OUT UINTN
*DataSize
,
732 OUT VOID
*Data OPTIONAL
737 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
739 UINTN VariableNameSize
;
741 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (DataSize
== NULL
)) {
742 return EFI_INVALID_PARAMETER
;
745 TempDataSize
= *DataSize
;
746 VariableNameSize
= StrSize (VariableName
);
747 SmmVariableHeader
= NULL
;
750 // If VariableName exceeds SMM payload limit. Return failure
752 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
753 return EFI_INVALID_PARAMETER
;
757 // Init the communicate buffer. The buffer data size is:
758 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
760 if (TempDataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
) {
762 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
764 TempDataSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
;
767 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ TempDataSize
;
769 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_VARIABLE
);
770 if (EFI_ERROR (Status
)) {
774 ASSERT (SmmVariableHeader
!= NULL
);
776 CopyGuid (&SmmVariableHeader
->Guid
, VendorGuid
);
777 SmmVariableHeader
->DataSize
= TempDataSize
;
778 SmmVariableHeader
->NameSize
= VariableNameSize
;
779 if (Attributes
== NULL
) {
780 SmmVariableHeader
->Attributes
= 0;
782 SmmVariableHeader
->Attributes
= *Attributes
;
785 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
790 Status
= SendCommunicateBuffer (PayloadSize
);
793 // Get data from SMM.
795 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_BUFFER_TOO_SMALL
)) {
797 // SMM CommBuffer DataSize can be a trimed value
798 // Only update DataSize when needed
800 *DataSize
= SmmVariableHeader
->DataSize
;
803 if (Attributes
!= NULL
) {
804 *Attributes
= SmmVariableHeader
->Attributes
;
807 if (EFI_ERROR (Status
)) {
812 CopyMem (Data
, (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, SmmVariableHeader
->DataSize
);
814 Status
= EFI_INVALID_PARAMETER
;
822 This code finds variable in storage blocks (Volatile or Non-Volatile).
824 Caution: This function may receive untrusted input.
825 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
827 @param[in] VariableName Name of Variable to be found.
828 @param[in] VendorGuid Variable vendor GUID.
829 @param[out] Attributes Attribute value of the variable found.
830 @param[in, out] DataSize Size of Data found. If size is less than the
831 data, this value contains the required size.
832 @param[out] Data Data pointer.
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.
842 RuntimeServiceGetVariable (
843 IN CHAR16
*VariableName
,
844 IN EFI_GUID
*VendorGuid
,
845 OUT UINT32
*Attributes OPTIONAL
,
846 IN OUT UINTN
*DataSize
,
852 if ((VariableName
== NULL
) || (VendorGuid
== NULL
) || (DataSize
== NULL
)) {
853 return EFI_INVALID_PARAMETER
;
856 if (VariableName
[0] == 0) {
857 return EFI_NOT_FOUND
;
860 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
861 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
862 Status
= FindVariableInRuntimeCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
864 Status
= FindVariableInSmm (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
867 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
873 Finds the next available variable in a runtime cache variable store.
875 @param[in, out] VariableNameSize Size of the variable name.
876 @param[in, out] VariableName Pointer to variable name.
877 @param[in, out] VendorGuid Variable Vendor Guid.
879 @retval EFI_INVALID_PARAMETER Invalid parameter.
880 @retval EFI_SUCCESS Find the specified variable.
881 @retval EFI_NOT_FOUND Not found.
882 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
886 GetNextVariableNameInRuntimeCache (
887 IN OUT UINTN
*VariableNameSize
,
888 IN OUT CHAR16
*VariableName
,
889 IN OUT EFI_GUID
*VendorGuid
894 VARIABLE_HEADER
*VariablePtr
;
895 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
897 Status
= EFI_NOT_FOUND
;
900 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
901 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
902 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
903 // cache read lock should always be free when entering this function.
905 ASSERT (!mVariableRuntimeCacheReadLock
);
907 CheckForRuntimeCacheSync ();
909 mVariableRuntimeCacheReadLock
= TRUE
;
910 if (!mVariableRuntimeCachePendingUpdate
) {
912 // 0: Volatile, 1: HOB, 2: Non-Volatile.
913 // The index and attributes mapping must be kept in this order as FindVariable
914 // makes use of this mapping to implement search algorithm.
916 VariableStoreHeader
[VariableStoreTypeVolatile
] = mVariableRuntimeVolatileCacheBuffer
;
917 VariableStoreHeader
[VariableStoreTypeHob
] = mVariableRuntimeHobCacheBuffer
;
918 VariableStoreHeader
[VariableStoreTypeNv
] = mVariableRuntimeNvCacheBuffer
;
920 Status
= VariableServiceGetNextVariableInternal (
927 if (!EFI_ERROR (Status
)) {
928 VarNameSize
= NameSizeOfVariable (VariablePtr
, mVariableAuthFormat
);
929 ASSERT (VarNameSize
!= 0);
930 if (VarNameSize
<= *VariableNameSize
) {
931 CopyMem (VariableName
, GetVariableNamePtr (VariablePtr
, mVariableAuthFormat
), VarNameSize
);
932 CopyMem (VendorGuid
, GetVendorGuidPtr (VariablePtr
, mVariableAuthFormat
), sizeof (EFI_GUID
));
933 Status
= EFI_SUCCESS
;
935 Status
= EFI_BUFFER_TOO_SMALL
;
938 *VariableNameSize
= VarNameSize
;
942 mVariableRuntimeCacheReadLock
= FALSE
;
948 Finds the next available variable in a SMM variable store.
950 @param[in, out] VariableNameSize Size of the variable name.
951 @param[in, out] VariableName Pointer to variable name.
952 @param[in, out] VendorGuid Variable Vendor Guid.
954 @retval EFI_INVALID_PARAMETER Invalid parameter.
955 @retval EFI_SUCCESS Find the specified variable.
956 @retval EFI_NOT_FOUND Not found.
957 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
961 GetNextVariableNameInSmm (
962 IN OUT UINTN
*VariableNameSize
,
963 IN OUT CHAR16
*VariableName
,
964 IN OUT EFI_GUID
*VendorGuid
969 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*SmmGetNextVariableName
;
970 UINTN OutVariableNameSize
;
971 UINTN InVariableNameSize
;
973 OutVariableNameSize
= *VariableNameSize
;
974 InVariableNameSize
= StrSize (VariableName
);
975 SmmGetNextVariableName
= NULL
;
978 // If input string exceeds SMM payload limit. Return failure
980 if (InVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
981 return EFI_INVALID_PARAMETER
;
985 // Init the communicate buffer. The buffer data size is:
986 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
988 if (OutVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
990 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
992 OutVariableNameSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
996 // Payload should be Guid + NameSize + MAX of Input & Output buffer
998 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + MAX (OutVariableNameSize
, InVariableNameSize
);
1000 Status
= InitCommunicateBuffer ((VOID
**)&SmmGetNextVariableName
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
);
1001 if (EFI_ERROR (Status
)) {
1005 ASSERT (SmmGetNextVariableName
!= NULL
);
1008 // SMM comm buffer->NameSize is buffer size for return string
1010 SmmGetNextVariableName
->NameSize
= OutVariableNameSize
;
1012 CopyGuid (&SmmGetNextVariableName
->Guid
, VendorGuid
);
1014 // Copy whole string
1016 CopyMem (SmmGetNextVariableName
->Name
, VariableName
, InVariableNameSize
);
1017 if (OutVariableNameSize
> InVariableNameSize
) {
1018 ZeroMem ((UINT8
*)SmmGetNextVariableName
->Name
+ InVariableNameSize
, OutVariableNameSize
- InVariableNameSize
);
1024 Status
= SendCommunicateBuffer (PayloadSize
);
1027 // Get data from SMM.
1029 if ((Status
== EFI_SUCCESS
) || (Status
== EFI_BUFFER_TOO_SMALL
)) {
1031 // SMM CommBuffer NameSize can be a trimed value
1032 // Only update VariableNameSize when needed
1034 *VariableNameSize
= SmmGetNextVariableName
->NameSize
;
1037 if (EFI_ERROR (Status
)) {
1041 CopyGuid (VendorGuid
, &SmmGetNextVariableName
->Guid
);
1042 CopyMem (VariableName
, SmmGetNextVariableName
->Name
, SmmGetNextVariableName
->NameSize
);
1049 This code Finds the Next available variable.
1051 @param[in, out] VariableNameSize Size of the variable name.
1052 @param[in, out] VariableName Pointer to variable name.
1053 @param[in, out] VendorGuid Variable Vendor Guid.
1055 @retval EFI_INVALID_PARAMETER Invalid parameter.
1056 @retval EFI_SUCCESS Find the specified variable.
1057 @retval EFI_NOT_FOUND Not found.
1058 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
1063 RuntimeServiceGetNextVariableName (
1064 IN OUT UINTN
*VariableNameSize
,
1065 IN OUT CHAR16
*VariableName
,
1066 IN OUT EFI_GUID
*VendorGuid
1072 Status
= EFI_NOT_FOUND
;
1074 if ((VariableNameSize
== NULL
) || (VariableName
== NULL
) || (VendorGuid
== NULL
)) {
1075 return EFI_INVALID_PARAMETER
;
1079 // Calculate the possible maximum length of name string, including the Null terminator.
1081 MaxLen
= *VariableNameSize
/ sizeof (CHAR16
);
1082 if ((MaxLen
== 0) || (StrnLenS (VariableName
, MaxLen
) == MaxLen
)) {
1084 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
1085 // follow spec to return EFI_INVALID_PARAMETER.
1087 return EFI_INVALID_PARAMETER
;
1090 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1091 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
1092 Status
= GetNextVariableNameInRuntimeCache (VariableNameSize
, VariableName
, VendorGuid
);
1094 Status
= GetNextVariableNameInSmm (VariableNameSize
, VariableName
, VendorGuid
);
1097 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1103 This code sets variable in storage blocks (Volatile or Non-Volatile).
1105 Caution: This function may receive untrusted input.
1106 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
1108 @param[in] VariableName Name of Variable to be found.
1109 @param[in] VendorGuid Variable vendor GUID.
1110 @param[in] Attributes Attribute value of the variable found
1111 @param[in] DataSize Size of Data found. If size is less than the
1112 data, this value contains the required size.
1113 @param[in] Data Data pointer.
1115 @retval EFI_INVALID_PARAMETER Invalid parameter.
1116 @retval EFI_SUCCESS Set successfully.
1117 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
1118 @retval EFI_NOT_FOUND Not found.
1119 @retval EFI_WRITE_PROTECTED Variable is read-only.
1124 RuntimeServiceSetVariable (
1125 IN CHAR16
*VariableName
,
1126 IN EFI_GUID
*VendorGuid
,
1127 IN UINT32 Attributes
,
1134 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
1135 UINTN VariableNameSize
;
1138 // Check input parameters.
1140 if ((VariableName
== NULL
) || (VariableName
[0] == 0) || (VendorGuid
== NULL
)) {
1141 return EFI_INVALID_PARAMETER
;
1144 if ((DataSize
!= 0) && (Data
== NULL
)) {
1145 return EFI_INVALID_PARAMETER
;
1148 VariableNameSize
= StrSize (VariableName
);
1149 SmmVariableHeader
= NULL
;
1152 // If VariableName or DataSize exceeds SMM payload limit. Return failure
1154 if ((VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
1155 (DataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
))
1157 return EFI_INVALID_PARAMETER
;
1160 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1163 // Init the communicate buffer. The buffer data size is:
1164 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
1166 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ DataSize
;
1167 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_SET_VARIABLE
);
1168 if (EFI_ERROR (Status
)) {
1172 ASSERT (SmmVariableHeader
!= NULL
);
1174 CopyGuid ((EFI_GUID
*)&SmmVariableHeader
->Guid
, VendorGuid
);
1175 SmmVariableHeader
->DataSize
= DataSize
;
1176 SmmVariableHeader
->NameSize
= VariableNameSize
;
1177 SmmVariableHeader
->Attributes
= Attributes
;
1178 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
1179 CopyMem ((UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, Data
, DataSize
);
1182 // Send data to SMM.
1184 Status
= SendCommunicateBuffer (PayloadSize
);
1187 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1189 if (!EfiAtRuntime ()) {
1190 if (!EFI_ERROR (Status
)) {
1202 This code returns information about the EFI variables.
1204 @param[in] Attributes Attributes bitmask to specify the type of variables
1205 on which to return information.
1206 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1207 for the EFI variables associated with the attributes specified.
1208 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1209 for EFI variables associated with the attributes specified.
1210 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1211 associated with the attributes specified.
1213 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
1214 @retval EFI_SUCCESS Query successfully.
1215 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
1220 RuntimeServiceQueryVariableInfo (
1221 IN UINT32 Attributes
,
1222 OUT UINT64
*MaximumVariableStorageSize
,
1223 OUT UINT64
*RemainingVariableStorageSize
,
1224 OUT UINT64
*MaximumVariableSize
1229 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*SmmQueryVariableInfo
;
1231 SmmQueryVariableInfo
= NULL
;
1233 if ((MaximumVariableStorageSize
== NULL
) || (RemainingVariableStorageSize
== NULL
) || (MaximumVariableSize
== NULL
) || (Attributes
== 0)) {
1234 return EFI_INVALID_PARAMETER
;
1237 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1240 // Init the communicate buffer. The buffer data size is:
1241 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
1243 PayloadSize
= sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
1244 Status
= InitCommunicateBuffer ((VOID
**)&SmmQueryVariableInfo
, PayloadSize
, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
);
1245 if (EFI_ERROR (Status
)) {
1249 ASSERT (SmmQueryVariableInfo
!= NULL
);
1251 SmmQueryVariableInfo
->Attributes
= Attributes
;
1254 // Send data to SMM.
1256 Status
= SendCommunicateBuffer (PayloadSize
);
1257 if (EFI_ERROR (Status
)) {
1262 // Get data from SMM.
1264 *MaximumVariableSize
= SmmQueryVariableInfo
->MaximumVariableSize
;
1265 *MaximumVariableStorageSize
= SmmQueryVariableInfo
->MaximumVariableStorageSize
;
1266 *RemainingVariableStorageSize
= SmmQueryVariableInfo
->RemainingVariableStorageSize
;
1269 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1274 Exit Boot Services Event notification handler.
1276 Notify SMM variable driver about the event.
1278 @param[in] Event Event whose notification function is being invoked.
1279 @param[in] Context Pointer to the notification function's context.
1284 OnExitBootServices (
1290 // Init the communicate buffer. The buffer data size is:
1291 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
1293 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
);
1296 // Send data to SMM.
1298 SendCommunicateBuffer (0);
1302 On Ready To Boot Services Event notification handler.
1304 Notify SMM variable driver about the event.
1306 @param[in] Event Event whose notification function is being invoked
1307 @param[in] Context Pointer to the notification function's context
1318 // Init the communicate buffer. The buffer data size is:
1319 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
1321 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT
);
1324 // Send data to SMM.
1326 SendCommunicateBuffer (0);
1329 // Install the system configuration table for variable info data captured
1331 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
) && FeaturePcdGet (PcdVariableCollectStatistics
)) {
1332 if (mVariableAuthFormat
) {
1333 gBS
->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid
, mVariableInfo
);
1335 gBS
->InstallConfigurationTable (&gEfiVariableGuid
, mVariableInfo
);
1339 gBS
->CloseEvent (Event
);
1343 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
1345 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1346 It convers pointer to new virtual address.
1348 @param[in] Event Event whose notification function is being invoked.
1349 @param[in] Context Pointer to the notification function's context.
1354 VariableAddressChangeEvent (
1359 EfiConvertPointer (0x0, (VOID
**)&mVariableBuffer
);
1360 EfiConvertPointer (0x0, (VOID
**)&mMmCommunication2
);
1361 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**)&mVariableRuntimeHobCacheBuffer
);
1362 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**)&mVariableRuntimeNvCacheBuffer
);
1363 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**)&mVariableRuntimeVolatileCacheBuffer
);
1367 This code gets variable payload size.
1369 @param[out] VariablePayloadSize Output pointer to variable payload size.
1371 @retval EFI_SUCCESS Get successfully.
1372 @retval Others Get unsuccessfully.
1377 GetVariablePayloadSize (
1378 OUT UINTN
*VariablePayloadSize
1382 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*SmmGetPayloadSize
;
1383 EFI_MM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1384 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1388 SmmGetPayloadSize
= NULL
;
1391 if (VariablePayloadSize
== NULL
) {
1392 return EFI_INVALID_PARAMETER
;
1395 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1398 // Init the communicate buffer. The buffer data size is:
1399 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
1401 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
1402 CommBuffer
= AllocateZeroPool (CommSize
);
1403 if (CommBuffer
== NULL
) {
1404 Status
= EFI_OUT_OF_RESOURCES
;
1408 SmmCommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)CommBuffer
;
1409 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1410 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
1412 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
1413 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE
;
1414 SmmGetPayloadSize
= (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*)SmmVariableFunctionHeader
->Data
;
1417 // Send data to SMM.
1419 Status
= mMmCommunication2
->Communicate (mMmCommunication2
, CommBuffer
, CommBuffer
, &CommSize
);
1420 ASSERT_EFI_ERROR (Status
);
1422 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1423 if (EFI_ERROR (Status
)) {
1428 // Get data from SMM.
1430 *VariablePayloadSize
= SmmGetPayloadSize
->VariablePayloadSize
;
1433 if (CommBuffer
!= NULL
) {
1434 FreePool (CommBuffer
);
1437 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1442 This code gets information needed from SMM for runtime cache initialization.
1444 @param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes.
1445 @param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes.
1446 @param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes.
1447 @param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used.
1449 @retval EFI_SUCCESS Retrieved the size successfully.
1450 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
1451 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
1452 @retval Others Could not retrieve the size successfully.
1456 GetRuntimeCacheInfo (
1457 OUT UINTN
*TotalHobStorageSize
,
1458 OUT UINTN
*TotalNvStorageSize
,
1459 OUT UINTN
*TotalVolatileStorageSize
,
1460 OUT BOOLEAN
*AuthenticatedVariableUsage
1464 SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
*SmmGetRuntimeCacheInfo
;
1465 EFI_MM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1466 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1470 SmmGetRuntimeCacheInfo
= NULL
;
1471 CommBuffer
= mVariableBuffer
;
1473 if ((TotalHobStorageSize
== NULL
) || (TotalNvStorageSize
== NULL
) || (TotalVolatileStorageSize
== NULL
) || (AuthenticatedVariableUsage
== NULL
)) {
1474 return EFI_INVALID_PARAMETER
;
1477 if (CommBuffer
== NULL
) {
1478 return EFI_OUT_OF_RESOURCES
;
1481 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1483 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
);
1484 ZeroMem (CommBuffer
, CommSize
);
1486 SmmCommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)CommBuffer
;
1487 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1488 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
);
1490 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
1491 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO
;
1492 SmmGetRuntimeCacheInfo
= (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
*)SmmVariableFunctionHeader
->Data
;
1495 // Send data to SMM.
1497 Status
= mMmCommunication2
->Communicate (mMmCommunication2
, CommBuffer
, CommBuffer
, &CommSize
);
1498 ASSERT_EFI_ERROR (Status
);
1499 if (CommSize
<= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
1500 Status
= EFI_BAD_BUFFER_SIZE
;
1504 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1505 if (EFI_ERROR (Status
)) {
1510 // Get data from SMM.
1512 *TotalHobStorageSize
= SmmGetRuntimeCacheInfo
->TotalHobStorageSize
;
1513 *TotalNvStorageSize
= SmmGetRuntimeCacheInfo
->TotalNvStorageSize
;
1514 *TotalVolatileStorageSize
= SmmGetRuntimeCacheInfo
->TotalVolatileStorageSize
;
1515 *AuthenticatedVariableUsage
= SmmGetRuntimeCacheInfo
->AuthenticatedVariableUsage
;
1518 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1523 Sends the runtime variable cache context information to SMM.
1525 @retval EFI_SUCCESS Retrieved the size successfully.
1526 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
1527 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
1528 @retval Others Could not retrieve the size successfully.;
1532 SendRuntimeVariableCacheContextToSmm (
1537 SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
*SmmRuntimeVarCacheContext
;
1538 EFI_MM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1539 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1543 SmmRuntimeVarCacheContext
= NULL
;
1544 CommBuffer
= mVariableBuffer
;
1546 if (CommBuffer
== NULL
) {
1547 return EFI_OUT_OF_RESOURCES
;
1550 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1553 // Init the communicate buffer. The buffer data size is:
1554 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
1556 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
);
1557 ZeroMem (CommBuffer
, CommSize
);
1559 SmmCommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*)CommBuffer
;
1560 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1561 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
);
1563 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
1564 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT
;
1565 SmmRuntimeVarCacheContext
= (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
*)SmmVariableFunctionHeader
->Data
;
1567 SmmRuntimeVarCacheContext
->RuntimeHobCache
= mVariableRuntimeHobCacheBuffer
;
1568 SmmRuntimeVarCacheContext
->RuntimeVolatileCache
= mVariableRuntimeVolatileCacheBuffer
;
1569 SmmRuntimeVarCacheContext
->RuntimeNvCache
= mVariableRuntimeNvCacheBuffer
;
1570 SmmRuntimeVarCacheContext
->PendingUpdate
= &mVariableRuntimeCachePendingUpdate
;
1571 SmmRuntimeVarCacheContext
->ReadLock
= &mVariableRuntimeCacheReadLock
;
1572 SmmRuntimeVarCacheContext
->HobFlushComplete
= &mHobFlushComplete
;
1575 // Request to unblock this region to be accessible from inside MM environment
1576 // These fields "should" be all on the same page, but just to be on the safe side...
1578 Status
= MmUnblockMemoryRequest (
1579 (EFI_PHYSICAL_ADDRESS
)ALIGN_VALUE ((UINTN
)SmmRuntimeVarCacheContext
->PendingUpdate
- EFI_PAGE_SIZE
+ 1, EFI_PAGE_SIZE
),
1580 EFI_SIZE_TO_PAGES (sizeof (mVariableRuntimeCachePendingUpdate
))
1582 if ((Status
!= EFI_UNSUPPORTED
) && EFI_ERROR (Status
)) {
1586 Status
= MmUnblockMemoryRequest (
1587 (EFI_PHYSICAL_ADDRESS
)ALIGN_VALUE ((UINTN
)SmmRuntimeVarCacheContext
->ReadLock
- EFI_PAGE_SIZE
+ 1, EFI_PAGE_SIZE
),
1588 EFI_SIZE_TO_PAGES (sizeof (mVariableRuntimeCacheReadLock
))
1590 if ((Status
!= EFI_UNSUPPORTED
) && EFI_ERROR (Status
)) {
1594 Status
= MmUnblockMemoryRequest (
1595 (EFI_PHYSICAL_ADDRESS
)ALIGN_VALUE ((UINTN
)SmmRuntimeVarCacheContext
->HobFlushComplete
- EFI_PAGE_SIZE
+ 1, EFI_PAGE_SIZE
),
1596 EFI_SIZE_TO_PAGES (sizeof (mHobFlushComplete
))
1598 if ((Status
!= EFI_UNSUPPORTED
) && EFI_ERROR (Status
)) {
1603 // Send data to SMM.
1605 Status
= mMmCommunication2
->Communicate (mMmCommunication2
, CommBuffer
, CommBuffer
, &CommSize
);
1606 ASSERT_EFI_ERROR (Status
);
1607 if (CommSize
<= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
1608 Status
= EFI_BAD_BUFFER_SIZE
;
1612 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1613 if (EFI_ERROR (Status
)) {
1618 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1623 Initialize variable service and install Variable Architectural protocol.
1625 @param[in] Event Event whose notification function is being invoked.
1626 @param[in] Context Pointer to the notification function's context.
1638 Status
= gBS
->LocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
1639 if (EFI_ERROR (Status
)) {
1643 Status
= gBS
->LocateProtocol (&gEfiMmCommunication2ProtocolGuid
, NULL
, (VOID
**)&mMmCommunication2
);
1644 ASSERT_EFI_ERROR (Status
);
1647 // Allocate memory for variable communicate buffer.
1649 Status
= GetVariablePayloadSize (&mVariableBufferPayloadSize
);
1650 ASSERT_EFI_ERROR (Status
);
1651 mVariableBufferSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ mVariableBufferPayloadSize
;
1652 mVariableBuffer
= AllocateRuntimePool (mVariableBufferSize
);
1653 ASSERT (mVariableBuffer
!= NULL
);
1656 // Save the buffer physical address used for SMM conmunication.
1658 mVariableBufferPhysical
= mVariableBuffer
;
1660 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
1661 DEBUG ((DEBUG_INFO
, "Variable driver runtime cache is enabled.\n"));
1663 // Allocate runtime variable cache memory buffers.
1665 Status
= GetRuntimeCacheInfo (
1666 &mVariableRuntimeHobCacheBufferSize
,
1667 &mVariableRuntimeNvCacheBufferSize
,
1668 &mVariableRuntimeVolatileCacheBufferSize
,
1669 &mVariableAuthFormat
1671 if (!EFI_ERROR (Status
)) {
1672 Status
= InitVariableCache (&mVariableRuntimeHobCacheBuffer
, &mVariableRuntimeHobCacheBufferSize
);
1673 if (!EFI_ERROR (Status
)) {
1674 Status
= InitVariableCache (&mVariableRuntimeNvCacheBuffer
, &mVariableRuntimeNvCacheBufferSize
);
1675 if (!EFI_ERROR (Status
)) {
1676 Status
= InitVariableCache (&mVariableRuntimeVolatileCacheBuffer
, &mVariableRuntimeVolatileCacheBufferSize
);
1677 if (!EFI_ERROR (Status
)) {
1678 Status
= SendRuntimeVariableCacheContextToSmm ();
1679 if (!EFI_ERROR (Status
)) {
1680 SyncRuntimeCache ();
1686 if (EFI_ERROR (Status
)) {
1687 mVariableRuntimeHobCacheBuffer
= NULL
;
1688 mVariableRuntimeNvCacheBuffer
= NULL
;
1689 mVariableRuntimeVolatileCacheBuffer
= NULL
;
1693 ASSERT_EFI_ERROR (Status
);
1695 DEBUG ((DEBUG_INFO
, "Variable driver runtime cache is disabled.\n"));
1698 gRT
->GetVariable
= RuntimeServiceGetVariable
;
1699 gRT
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
1700 gRT
->SetVariable
= RuntimeServiceSetVariable
;
1701 gRT
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
1704 // Install the Variable Architectural Protocol on a new handle.
1706 Status
= gBS
->InstallProtocolInterface (
1708 &gEfiVariableArchProtocolGuid
,
1709 EFI_NATIVE_INTERFACE
,
1712 ASSERT_EFI_ERROR (Status
);
1714 mVariableLock
.RequestToLock
= VariableLockRequestToLock
;
1715 Status
= gBS
->InstallMultipleProtocolInterfaces (
1717 &gEdkiiVariableLockProtocolGuid
,
1721 ASSERT_EFI_ERROR (Status
);
1723 mVarCheck
.RegisterSetVariableCheckHandler
= VarCheckRegisterSetVariableCheckHandler
;
1724 mVarCheck
.VariablePropertySet
= VarCheckVariablePropertySet
;
1725 mVarCheck
.VariablePropertyGet
= VarCheckVariablePropertyGet
;
1726 Status
= gBS
->InstallMultipleProtocolInterfaces (
1728 &gEdkiiVarCheckProtocolGuid
,
1732 ASSERT_EFI_ERROR (Status
);
1734 gBS
->CloseEvent (Event
);
1738 SMM Non-Volatile variable write service is ready notify event handler.
1740 @param[in] Event Event whose notification function is being invoked.
1741 @param[in] Context Pointer to the notification function's context.
1746 SmmVariableWriteReady (
1755 // Check whether the protocol is installed or not.
1757 Status
= gBS
->LocateProtocol (&gSmmVariableWriteGuid
, NULL
, (VOID
**)&ProtocolOps
);
1758 if (EFI_ERROR (Status
)) {
1763 // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
1764 // Secure Boot Policy Variable change. Record their initial value.
1766 RecordSecureBootPolicyVarData ();
1768 Status
= gBS
->InstallProtocolInterface (
1770 &gEfiVariableWriteArchProtocolGuid
,
1771 EFI_NATIVE_INTERFACE
,
1774 ASSERT_EFI_ERROR (Status
);
1776 gBS
->CloseEvent (Event
);
1780 Variable Driver main entry point. The Variable driver places the 4 EFI
1781 runtime services in the EFI System Table and installs arch protocols
1782 for variable read and write services being available. It also registers
1783 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1785 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1786 @param[in] SystemTable A pointer to the EFI System Table.
1788 @retval EFI_SUCCESS Variable service successfully initialized.
1793 VariableSmmRuntimeInitialize (
1794 IN EFI_HANDLE ImageHandle
,
1795 IN EFI_SYSTEM_TABLE
*SystemTable
1798 VOID
*SmmVariableRegistration
;
1799 VOID
*SmmVariableWriteRegistration
;
1800 EFI_EVENT OnReadyToBootEvent
;
1801 EFI_EVENT ExitBootServiceEvent
;
1802 EFI_EVENT LegacyBootEvent
;
1804 EfiInitializeLock (&mVariableServicesLock
, TPL_NOTIFY
);
1807 // Smm variable service is ready
1809 EfiCreateProtocolNotifyEvent (
1810 &gEfiSmmVariableProtocolGuid
,
1814 &SmmVariableRegistration
1818 // Smm Non-Volatile variable write service is ready
1820 EfiCreateProtocolNotifyEvent (
1821 &gSmmVariableWriteGuid
,
1823 SmmVariableWriteReady
,
1825 &SmmVariableWriteRegistration
1829 // Register the event to reclaim variable for OS usage.
1831 EfiCreateEventReadyToBootEx (
1839 // Register the event to inform SMM variable that it is at runtime.
1841 gBS
->CreateEventEx (
1846 &gEfiEventExitBootServicesGuid
,
1847 &ExitBootServiceEvent
1851 // Register the event to inform SMM variable that it is at runtime for legacy boot.
1852 // Reuse OnExitBootServices() here.
1854 EfiCreateEventLegacyBootEx (
1862 // Register the event to convert the pointer for runtime.
1864 gBS
->CreateEventEx (
1867 VariableAddressChangeEvent
,
1869 &gEfiEventVirtualAddressChangeGuid
,
1870 &mVirtualAddressChangeEvent
1873 // Initialize the VariablePolicy protocol and engine.
1874 VariablePolicySmmDxeMain (ImageHandle
, SystemTable
);