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>
39 #include <Guid/EventGroup.h>
40 #include <Guid/SmmVariableCommon.h>
42 #include "PrivilegePolymorphic.h"
43 #include "VariableParsing.h"
45 EFI_HANDLE mHandle
= NULL
;
46 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
= NULL
;
47 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
48 EFI_MM_COMMUNICATION2_PROTOCOL
*mMmCommunication2
= NULL
;
49 UINT8
*mVariableBuffer
= NULL
;
50 UINT8
*mVariableBufferPhysical
= NULL
;
51 VARIABLE_INFO_ENTRY
*mVariableInfo
= NULL
;
52 VARIABLE_STORE_HEADER
*mVariableRuntimeHobCacheBuffer
= NULL
;
53 VARIABLE_STORE_HEADER
*mVariableRuntimeNvCacheBuffer
= NULL
;
54 VARIABLE_STORE_HEADER
*mVariableRuntimeVolatileCacheBuffer
= NULL
;
55 UINTN mVariableBufferSize
;
56 UINTN mVariableRuntimeHobCacheBufferSize
;
57 UINTN mVariableRuntimeNvCacheBufferSize
;
58 UINTN mVariableRuntimeVolatileCacheBufferSize
;
59 UINTN mVariableBufferPayloadSize
;
60 BOOLEAN mVariableRuntimeCachePendingUpdate
;
61 BOOLEAN mVariableRuntimeCacheReadLock
;
62 BOOLEAN mVariableAuthFormat
;
63 BOOLEAN mHobFlushComplete
;
64 EFI_LOCK mVariableServicesLock
;
65 EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock
;
66 EDKII_VAR_CHECK_PROTOCOL mVarCheck
;
69 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
70 Record their initial State when variable write service is ready.
75 RecordSecureBootPolicyVarData(
80 Acquires lock only at boot time. Simply returns at runtime.
82 This is a temperary function that will be removed when
83 EfiAcquireLock() in UefiLib can handle the call in UEFI
84 Runtimer driver in RT phase.
85 It calls EfiAcquireLock() at boot time, and simply returns
88 @param Lock A pointer to the lock to acquire.
92 AcquireLockOnlyAtBootTime (
96 if (!EfiAtRuntime ()) {
97 EfiAcquireLock (Lock
);
102 Releases lock only at boot time. Simply returns at runtime.
104 This is a temperary function which will be removed when
105 EfiReleaseLock() in UefiLib can handle the call in UEFI
106 Runtimer driver in RT phase.
107 It calls EfiReleaseLock() at boot time and simply returns
110 @param Lock A pointer to the lock to release.
114 ReleaseLockOnlyAtBootTime (
118 if (!EfiAtRuntime ()) {
119 EfiReleaseLock (Lock
);
124 Return TRUE if ExitBootServices () has been called.
126 @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.
133 return EfiAtRuntime ();
137 Initialize the variable cache buffer as an empty variable store.
139 @param[out] VariableCacheBuffer A pointer to pointer of a cache variable store.
140 @param[in,out] TotalVariableCacheSize On input, the minimum size needed for the UEFI variable store cache
141 buffer that is allocated. On output, the actual size of the buffer allocated.
142 If TotalVariableCacheSize is zero, a buffer will not be allocated and the
143 function will return with EFI_SUCCESS.
145 @retval EFI_SUCCESS The variable cache was allocated and initialized successfully.
146 @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid variable store size was specified.
147 @retval EFI_OUT_OF_RESOURCES Insufficient resources are available to allocate the variable store cache buffer.
152 OUT VARIABLE_STORE_HEADER
**VariableCacheBuffer
,
153 IN OUT UINTN
*TotalVariableCacheSize
156 VARIABLE_STORE_HEADER
*VariableCacheStorePtr
;
158 if (TotalVariableCacheSize
== NULL
) {
159 return EFI_INVALID_PARAMETER
;
161 if (*TotalVariableCacheSize
== 0) {
164 if (VariableCacheBuffer
== NULL
|| *TotalVariableCacheSize
< sizeof (VARIABLE_STORE_HEADER
)) {
165 return EFI_INVALID_PARAMETER
;
167 *TotalVariableCacheSize
= ALIGN_VALUE (*TotalVariableCacheSize
, sizeof (UINT32
));
170 // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)
172 *VariableCacheBuffer
= (VARIABLE_STORE_HEADER
*) AllocateRuntimePages (
173 EFI_SIZE_TO_PAGES (*TotalVariableCacheSize
)
175 if (*VariableCacheBuffer
== NULL
) {
176 return EFI_OUT_OF_RESOURCES
;
178 VariableCacheStorePtr
= *VariableCacheBuffer
;
179 SetMem32 ((VOID
*) VariableCacheStorePtr
, *TotalVariableCacheSize
, (UINT32
) 0xFFFFFFFF);
181 ZeroMem ((VOID
*) VariableCacheStorePtr
, sizeof (VARIABLE_STORE_HEADER
));
182 VariableCacheStorePtr
->Size
= (UINT32
) *TotalVariableCacheSize
;
183 VariableCacheStorePtr
->Format
= VARIABLE_STORE_FORMATTED
;
184 VariableCacheStorePtr
->State
= VARIABLE_STORE_HEALTHY
;
190 Initialize the communicate buffer using DataSize and Function.
192 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
195 Caution: This function may receive untrusted input.
196 The data size external input, so this function will validate it carefully to avoid buffer overflow.
198 @param[out] DataPtr Points to the data in the communicate buffer.
199 @param[in] DataSize The data size to send to SMM.
200 @param[in] Function The function number to initialize the communicate header.
202 @retval EFI_INVALID_PARAMETER The data size is too big.
203 @retval EFI_SUCCESS Find the specified variable.
207 InitCommunicateBuffer (
208 OUT VOID
**DataPtr OPTIONAL
,
213 EFI_MM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
214 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
217 if (DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
> mVariableBufferSize
) {
218 return EFI_INVALID_PARAMETER
;
221 SmmCommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*) mVariableBuffer
;
222 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
223 SmmCommunicateHeader
->MessageLength
= DataSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
225 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
226 SmmVariableFunctionHeader
->Function
= Function
;
227 if (DataPtr
!= NULL
) {
228 *DataPtr
= SmmVariableFunctionHeader
->Data
;
236 Send the data in communicate buffer to SMM.
238 @param[in] DataSize This size of the function header and the data.
240 @retval EFI_SUCCESS Success is returned from the functin in SMM.
241 @retval Others Failure is returned from the function in SMM.
245 SendCommunicateBuffer (
251 EFI_MM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
252 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
254 CommSize
= DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
255 Status
= mMmCommunication2
->Communicate (mMmCommunication2
,
256 mVariableBufferPhysical
,
259 ASSERT_EFI_ERROR (Status
);
261 SmmCommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*) mVariableBuffer
;
262 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
263 return SmmVariableFunctionHeader
->ReturnStatus
;
267 Mark a variable that will become read-only after leaving the DXE phase of execution.
269 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
270 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
271 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
273 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
274 as pending to be read-only.
275 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
276 Or VariableName is an empty string.
277 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
278 already been signaled.
279 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
283 VariableLockRequestToLock (
284 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
285 IN CHAR16
*VariableName
,
286 IN EFI_GUID
*VendorGuid
290 UINTN VariableNameSize
;
292 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
294 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
295 return EFI_INVALID_PARAMETER
;
298 VariableNameSize
= StrSize (VariableName
);
299 VariableToLock
= NULL
;
302 // If VariableName exceeds SMM payload limit. Return failure
304 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
)) {
305 return EFI_INVALID_PARAMETER
;
308 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
311 // Init the communicate buffer. The buffer data size is:
312 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
314 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
) + VariableNameSize
;
315 Status
= InitCommunicateBuffer ((VOID
**) &VariableToLock
, PayloadSize
, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
);
316 if (EFI_ERROR (Status
)) {
319 ASSERT (VariableToLock
!= NULL
);
321 CopyGuid (&VariableToLock
->Guid
, VendorGuid
);
322 VariableToLock
->NameSize
= VariableNameSize
;
323 CopyMem (VariableToLock
->Name
, VariableName
, VariableToLock
->NameSize
);
328 Status
= SendCommunicateBuffer (PayloadSize
);
331 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
336 Register SetVariable check handler.
338 @param[in] Handler Pointer to check handler.
340 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
341 @retval EFI_INVALID_PARAMETER Handler is NULL.
342 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
343 already been signaled.
344 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
345 @retval EFI_UNSUPPORTED This interface is not implemented.
346 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
351 VarCheckRegisterSetVariableCheckHandler (
352 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
355 return EFI_UNSUPPORTED
;
359 Variable property set.
361 @param[in] Name Pointer to the variable name.
362 @param[in] Guid Pointer to the vendor GUID.
363 @param[in] VariableProperty Pointer to the input variable property.
365 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
366 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
367 or the fields of VariableProperty are not valid.
368 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
369 already been signaled.
370 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
375 VarCheckVariablePropertySet (
378 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
382 UINTN VariableNameSize
;
384 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
386 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
387 return EFI_INVALID_PARAMETER
;
390 if (VariableProperty
== NULL
) {
391 return EFI_INVALID_PARAMETER
;
394 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
395 return EFI_INVALID_PARAMETER
;
398 VariableNameSize
= StrSize (Name
);
399 CommVariableProperty
= NULL
;
402 // If VariableName exceeds SMM payload limit. Return failure
404 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
405 return EFI_INVALID_PARAMETER
;
408 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
411 // Init the communicate buffer. The buffer data size is:
412 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
414 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
415 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
);
416 if (EFI_ERROR (Status
)) {
419 ASSERT (CommVariableProperty
!= NULL
);
421 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
422 CopyMem (&CommVariableProperty
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
423 CommVariableProperty
->NameSize
= VariableNameSize
;
424 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
429 Status
= SendCommunicateBuffer (PayloadSize
);
432 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
437 Variable property get.
439 @param[in] Name Pointer to the variable name.
440 @param[in] Guid Pointer to the vendor GUID.
441 @param[out] VariableProperty Pointer to the output variable property.
443 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
444 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
445 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
450 VarCheckVariablePropertyGet (
453 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
457 UINTN VariableNameSize
;
459 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
461 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
462 return EFI_INVALID_PARAMETER
;
465 if (VariableProperty
== NULL
) {
466 return EFI_INVALID_PARAMETER
;
469 VariableNameSize
= StrSize (Name
);
470 CommVariableProperty
= NULL
;
473 // If VariableName exceeds SMM payload limit. Return failure
475 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
476 return EFI_INVALID_PARAMETER
;
479 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
482 // Init the communicate buffer. The buffer data size is:
483 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
485 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
486 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
);
487 if (EFI_ERROR (Status
)) {
490 ASSERT (CommVariableProperty
!= NULL
);
492 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
493 CommVariableProperty
->NameSize
= VariableNameSize
;
494 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
499 Status
= SendCommunicateBuffer (PayloadSize
);
500 if (Status
== EFI_SUCCESS
) {
501 CopyMem (VariableProperty
, &CommVariableProperty
->VariableProperty
, sizeof (*VariableProperty
));
505 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
510 Signals SMM to synchronize any pending variable updates with the runtime cache(s).
519 // Init the communicate buffer. The buffer data size is:
520 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
522 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE
);
527 SendCommunicateBuffer (0);
531 Check whether a SMI must be triggered to retrieve pending cache updates.
533 If the variable HOB was finished being flushed since the last check for a runtime cache update, this function
534 will prevent the HOB cache from being used for future runtime cache hits.
538 CheckForRuntimeCacheSync (
542 if (mVariableRuntimeCachePendingUpdate
) {
545 ASSERT (!mVariableRuntimeCachePendingUpdate
);
548 // The HOB variable data may have finished being flushed in the runtime cache sync update
550 if (mHobFlushComplete
&& mVariableRuntimeHobCacheBuffer
!= NULL
) {
551 if (!EfiAtRuntime ()) {
552 FreePages (mVariableRuntimeHobCacheBuffer
, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize
));
554 mVariableRuntimeHobCacheBuffer
= NULL
;
559 Finds the given variable in a runtime cache variable store.
561 Caution: This function may receive untrusted input.
562 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
564 @param[in] VariableName Name of Variable to be found.
565 @param[in] VendorGuid Variable vendor GUID.
566 @param[out] Attributes Attribute value of the variable found.
567 @param[in, out] DataSize Size of Data found. If size is less than the
568 data, this value contains the required size.
569 @param[out] Data Data pointer.
571 @retval EFI_SUCCESS Found the specified variable.
572 @retval EFI_INVALID_PARAMETER Invalid parameter.
573 @retval EFI_NOT_FOUND The specified variable could not be found.
577 FindVariableInRuntimeCache (
578 IN CHAR16
*VariableName
,
579 IN EFI_GUID
*VendorGuid
,
580 OUT UINT32
*Attributes OPTIONAL
,
581 IN OUT UINTN
*DataSize
,
582 OUT VOID
*Data OPTIONAL
587 VARIABLE_POINTER_TRACK RtPtrTrack
;
588 VARIABLE_STORE_TYPE StoreType
;
589 VARIABLE_STORE_HEADER
*VariableStoreList
[VariableStoreTypeMax
];
591 Status
= EFI_NOT_FOUND
;
593 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
594 return EFI_INVALID_PARAMETER
;
597 ZeroMem (&RtPtrTrack
, sizeof (RtPtrTrack
));
600 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
601 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
602 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
603 // cache read lock should always be free when entering this function.
605 ASSERT (!mVariableRuntimeCacheReadLock
);
607 mVariableRuntimeCacheReadLock
= TRUE
;
608 CheckForRuntimeCacheSync ();
610 if (!mVariableRuntimeCachePendingUpdate
) {
612 // 0: Volatile, 1: HOB, 2: Non-Volatile.
613 // The index and attributes mapping must be kept in this order as FindVariable
614 // makes use of this mapping to implement search algorithm.
616 VariableStoreList
[VariableStoreTypeVolatile
] = mVariableRuntimeVolatileCacheBuffer
;
617 VariableStoreList
[VariableStoreTypeHob
] = mVariableRuntimeHobCacheBuffer
;
618 VariableStoreList
[VariableStoreTypeNv
] = mVariableRuntimeNvCacheBuffer
;
620 for (StoreType
= (VARIABLE_STORE_TYPE
) 0; StoreType
< VariableStoreTypeMax
; StoreType
++) {
621 if (VariableStoreList
[StoreType
] == NULL
) {
625 RtPtrTrack
.StartPtr
= GetStartPointer (VariableStoreList
[StoreType
]);
626 RtPtrTrack
.EndPtr
= GetEndPointer (VariableStoreList
[StoreType
]);
627 RtPtrTrack
.Volatile
= (BOOLEAN
) (StoreType
== VariableStoreTypeVolatile
);
629 Status
= FindVariableEx (VariableName
, VendorGuid
, FALSE
, &RtPtrTrack
, mVariableAuthFormat
);
630 if (!EFI_ERROR (Status
)) {
635 if (!EFI_ERROR (Status
)) {
639 TempDataSize
= DataSizeOfVariable (RtPtrTrack
.CurrPtr
, mVariableAuthFormat
);
640 ASSERT (TempDataSize
!= 0);
642 if (*DataSize
>= TempDataSize
) {
644 Status
= EFI_INVALID_PARAMETER
;
648 CopyMem (Data
, GetVariableDataPtr (RtPtrTrack
.CurrPtr
, mVariableAuthFormat
), TempDataSize
);
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 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
665 if (Attributes
!= NULL
&& RtPtrTrack
.CurrPtr
!= NULL
) {
666 *Attributes
= RtPtrTrack
.CurrPtr
->Attributes
;
669 mVariableRuntimeCacheReadLock
= FALSE
;
675 Finds the given variable in a variable store in SMM.
677 Caution: This function may receive untrusted input.
678 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
680 @param[in] VariableName Name of Variable to be found.
681 @param[in] VendorGuid Variable vendor GUID.
682 @param[out] Attributes Attribute value of the variable found.
683 @param[in, out] DataSize Size of Data found. If size is less than the
684 data, this value contains the required size.
685 @param[out] Data Data pointer.
687 @retval EFI_SUCCESS Found the specified variable.
688 @retval EFI_INVALID_PARAMETER Invalid parameter.
689 @retval EFI_NOT_FOUND The specified variable could not be found.
694 IN CHAR16
*VariableName
,
695 IN EFI_GUID
*VendorGuid
,
696 OUT UINT32
*Attributes OPTIONAL
,
697 IN OUT UINTN
*DataSize
,
698 OUT VOID
*Data OPTIONAL
703 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
705 UINTN VariableNameSize
;
707 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
708 return EFI_INVALID_PARAMETER
;
711 TempDataSize
= *DataSize
;
712 VariableNameSize
= StrSize (VariableName
);
713 SmmVariableHeader
= NULL
;
716 // If VariableName exceeds SMM payload limit. Return failure
718 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
719 return EFI_INVALID_PARAMETER
;
723 // Init the communicate buffer. The buffer data size is:
724 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
726 if (TempDataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
) {
728 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
730 TempDataSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
;
732 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ TempDataSize
;
734 Status
= InitCommunicateBuffer ((VOID
**) &SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_VARIABLE
);
735 if (EFI_ERROR (Status
)) {
738 ASSERT (SmmVariableHeader
!= NULL
);
740 CopyGuid (&SmmVariableHeader
->Guid
, VendorGuid
);
741 SmmVariableHeader
->DataSize
= TempDataSize
;
742 SmmVariableHeader
->NameSize
= VariableNameSize
;
743 if (Attributes
== NULL
) {
744 SmmVariableHeader
->Attributes
= 0;
746 SmmVariableHeader
->Attributes
= *Attributes
;
748 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
753 Status
= SendCommunicateBuffer (PayloadSize
);
756 // Get data from SMM.
758 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
760 // SMM CommBuffer DataSize can be a trimed value
761 // Only update DataSize when needed
763 *DataSize
= SmmVariableHeader
->DataSize
;
765 if (Attributes
!= NULL
) {
766 *Attributes
= SmmVariableHeader
->Attributes
;
769 if (EFI_ERROR (Status
)) {
774 CopyMem (Data
, (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, SmmVariableHeader
->DataSize
);
776 Status
= EFI_INVALID_PARAMETER
;
784 This code finds variable in storage blocks (Volatile or Non-Volatile).
786 Caution: This function may receive untrusted input.
787 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
789 @param[in] VariableName Name of Variable to be found.
790 @param[in] VendorGuid Variable vendor GUID.
791 @param[out] Attributes Attribute value of the variable found.
792 @param[in, out] DataSize Size of Data found. If size is less than the
793 data, this value contains the required size.
794 @param[out] Data Data pointer.
796 @retval EFI_INVALID_PARAMETER Invalid parameter.
797 @retval EFI_SUCCESS Find the specified variable.
798 @retval EFI_NOT_FOUND Not found.
799 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
804 RuntimeServiceGetVariable (
805 IN CHAR16
*VariableName
,
806 IN EFI_GUID
*VendorGuid
,
807 OUT UINT32
*Attributes OPTIONAL
,
808 IN OUT UINTN
*DataSize
,
814 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
815 return EFI_INVALID_PARAMETER
;
817 if (VariableName
[0] == 0) {
818 return EFI_NOT_FOUND
;
821 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
822 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
823 Status
= FindVariableInRuntimeCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
825 Status
= FindVariableInSmm (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
827 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
833 Finds the next available variable in a runtime cache variable store.
835 @param[in, out] VariableNameSize Size of the variable name.
836 @param[in, out] VariableName Pointer to variable name.
837 @param[in, out] VendorGuid Variable Vendor Guid.
839 @retval EFI_INVALID_PARAMETER Invalid parameter.
840 @retval EFI_SUCCESS Find the specified variable.
841 @retval EFI_NOT_FOUND Not found.
842 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
846 GetNextVariableNameInRuntimeCache (
847 IN OUT UINTN
*VariableNameSize
,
848 IN OUT CHAR16
*VariableName
,
849 IN OUT EFI_GUID
*VendorGuid
854 VARIABLE_HEADER
*VariablePtr
;
855 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
857 Status
= EFI_NOT_FOUND
;
860 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
861 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
862 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
863 // cache read lock should always be free when entering this function.
865 ASSERT (!mVariableRuntimeCacheReadLock
);
867 CheckForRuntimeCacheSync ();
869 mVariableRuntimeCacheReadLock
= TRUE
;
870 if (!mVariableRuntimeCachePendingUpdate
) {
872 // 0: Volatile, 1: HOB, 2: Non-Volatile.
873 // The index and attributes mapping must be kept in this order as FindVariable
874 // makes use of this mapping to implement search algorithm.
876 VariableStoreHeader
[VariableStoreTypeVolatile
] = mVariableRuntimeVolatileCacheBuffer
;
877 VariableStoreHeader
[VariableStoreTypeHob
] = mVariableRuntimeHobCacheBuffer
;
878 VariableStoreHeader
[VariableStoreTypeNv
] = mVariableRuntimeNvCacheBuffer
;
880 Status
= VariableServiceGetNextVariableInternal (
887 if (!EFI_ERROR (Status
)) {
888 VarNameSize
= NameSizeOfVariable (VariablePtr
, mVariableAuthFormat
);
889 ASSERT (VarNameSize
!= 0);
890 if (VarNameSize
<= *VariableNameSize
) {
891 CopyMem (VariableName
, GetVariableNamePtr (VariablePtr
, mVariableAuthFormat
), VarNameSize
);
892 CopyMem (VendorGuid
, GetVendorGuidPtr (VariablePtr
, mVariableAuthFormat
), sizeof (EFI_GUID
));
893 Status
= EFI_SUCCESS
;
895 Status
= EFI_BUFFER_TOO_SMALL
;
898 *VariableNameSize
= VarNameSize
;
901 mVariableRuntimeCacheReadLock
= FALSE
;
907 Finds the next available variable in a SMM variable store.
909 @param[in, out] VariableNameSize Size of the variable name.
910 @param[in, out] VariableName Pointer to variable name.
911 @param[in, out] VendorGuid Variable Vendor Guid.
913 @retval EFI_INVALID_PARAMETER Invalid parameter.
914 @retval EFI_SUCCESS Find the specified variable.
915 @retval EFI_NOT_FOUND Not found.
916 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
920 GetNextVariableNameInSmm (
921 IN OUT UINTN
*VariableNameSize
,
922 IN OUT CHAR16
*VariableName
,
923 IN OUT EFI_GUID
*VendorGuid
928 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*SmmGetNextVariableName
;
929 UINTN OutVariableNameSize
;
930 UINTN InVariableNameSize
;
932 OutVariableNameSize
= *VariableNameSize
;
933 InVariableNameSize
= StrSize (VariableName
);
934 SmmGetNextVariableName
= NULL
;
937 // If input string exceeds SMM payload limit. Return failure
939 if (InVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
940 return EFI_INVALID_PARAMETER
;
944 // Init the communicate buffer. The buffer data size is:
945 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
947 if (OutVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
949 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
951 OutVariableNameSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
954 // Payload should be Guid + NameSize + MAX of Input & Output buffer
956 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + MAX (OutVariableNameSize
, InVariableNameSize
);
958 Status
= InitCommunicateBuffer ((VOID
**)&SmmGetNextVariableName
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
);
959 if (EFI_ERROR (Status
)) {
962 ASSERT (SmmGetNextVariableName
!= NULL
);
965 // SMM comm buffer->NameSize is buffer size for return string
967 SmmGetNextVariableName
->NameSize
= OutVariableNameSize
;
969 CopyGuid (&SmmGetNextVariableName
->Guid
, VendorGuid
);
973 CopyMem (SmmGetNextVariableName
->Name
, VariableName
, InVariableNameSize
);
974 if (OutVariableNameSize
> InVariableNameSize
) {
975 ZeroMem ((UINT8
*) SmmGetNextVariableName
->Name
+ InVariableNameSize
, OutVariableNameSize
- InVariableNameSize
);
981 Status
= SendCommunicateBuffer (PayloadSize
);
984 // Get data from SMM.
986 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
988 // SMM CommBuffer NameSize can be a trimed value
989 // Only update VariableNameSize when needed
991 *VariableNameSize
= SmmGetNextVariableName
->NameSize
;
993 if (EFI_ERROR (Status
)) {
997 CopyGuid (VendorGuid
, &SmmGetNextVariableName
->Guid
);
998 CopyMem (VariableName
, SmmGetNextVariableName
->Name
, SmmGetNextVariableName
->NameSize
);
1005 This code Finds the Next available variable.
1007 @param[in, out] VariableNameSize Size of the variable name.
1008 @param[in, out] VariableName Pointer to variable name.
1009 @param[in, out] VendorGuid Variable Vendor Guid.
1011 @retval EFI_INVALID_PARAMETER Invalid parameter.
1012 @retval EFI_SUCCESS Find the specified variable.
1013 @retval EFI_NOT_FOUND Not found.
1014 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
1019 RuntimeServiceGetNextVariableName (
1020 IN OUT UINTN
*VariableNameSize
,
1021 IN OUT CHAR16
*VariableName
,
1022 IN OUT EFI_GUID
*VendorGuid
1028 Status
= EFI_NOT_FOUND
;
1030 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
1031 return EFI_INVALID_PARAMETER
;
1035 // Calculate the possible maximum length of name string, including the Null terminator.
1037 MaxLen
= *VariableNameSize
/ sizeof (CHAR16
);
1038 if ((MaxLen
== 0) || (StrnLenS (VariableName
, MaxLen
) == MaxLen
)) {
1040 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
1041 // follow spec to return EFI_INVALID_PARAMETER.
1043 return EFI_INVALID_PARAMETER
;
1046 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1047 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
1048 Status
= GetNextVariableNameInRuntimeCache (VariableNameSize
, VariableName
, VendorGuid
);
1050 Status
= GetNextVariableNameInSmm (VariableNameSize
, VariableName
, VendorGuid
);
1052 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1058 This code sets variable in storage blocks (Volatile or Non-Volatile).
1060 Caution: This function may receive untrusted input.
1061 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
1063 @param[in] VariableName Name of Variable to be found.
1064 @param[in] VendorGuid Variable vendor GUID.
1065 @param[in] Attributes Attribute value of the variable found
1066 @param[in] DataSize Size of Data found. If size is less than the
1067 data, this value contains the required size.
1068 @param[in] Data Data pointer.
1070 @retval EFI_INVALID_PARAMETER Invalid parameter.
1071 @retval EFI_SUCCESS Set successfully.
1072 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
1073 @retval EFI_NOT_FOUND Not found.
1074 @retval EFI_WRITE_PROTECTED Variable is read-only.
1079 RuntimeServiceSetVariable (
1080 IN CHAR16
*VariableName
,
1081 IN EFI_GUID
*VendorGuid
,
1082 IN UINT32 Attributes
,
1089 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
1090 UINTN VariableNameSize
;
1093 // Check input parameters.
1095 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
1096 return EFI_INVALID_PARAMETER
;
1099 if (DataSize
!= 0 && Data
== NULL
) {
1100 return EFI_INVALID_PARAMETER
;
1103 VariableNameSize
= StrSize (VariableName
);
1104 SmmVariableHeader
= NULL
;
1107 // If VariableName or DataSize exceeds SMM payload limit. Return failure
1109 if ((VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
1110 (DataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
)){
1111 return EFI_INVALID_PARAMETER
;
1114 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
1117 // Init the communicate buffer. The buffer data size is:
1118 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
1120 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ DataSize
;
1121 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_SET_VARIABLE
);
1122 if (EFI_ERROR (Status
)) {
1125 ASSERT (SmmVariableHeader
!= NULL
);
1127 CopyGuid ((EFI_GUID
*) &SmmVariableHeader
->Guid
, VendorGuid
);
1128 SmmVariableHeader
->DataSize
= DataSize
;
1129 SmmVariableHeader
->NameSize
= VariableNameSize
;
1130 SmmVariableHeader
->Attributes
= Attributes
;
1131 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
1132 CopyMem ((UINT8
*) SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, Data
, DataSize
);
1135 // Send data to SMM.
1137 Status
= SendCommunicateBuffer (PayloadSize
);
1140 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1142 if (!EfiAtRuntime ()) {
1143 if (!EFI_ERROR (Status
)) {
1155 This code returns information about the EFI variables.
1157 @param[in] Attributes Attributes bitmask to specify the type of variables
1158 on which to return information.
1159 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1160 for the EFI variables associated with the attributes specified.
1161 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1162 for EFI variables associated with the attributes specified.
1163 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1164 associated with the attributes specified.
1166 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
1167 @retval EFI_SUCCESS Query successfully.
1168 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
1173 RuntimeServiceQueryVariableInfo (
1174 IN UINT32 Attributes
,
1175 OUT UINT64
*MaximumVariableStorageSize
,
1176 OUT UINT64
*RemainingVariableStorageSize
,
1177 OUT UINT64
*MaximumVariableSize
1182 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*SmmQueryVariableInfo
;
1184 SmmQueryVariableInfo
= NULL
;
1186 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
1187 return EFI_INVALID_PARAMETER
;
1190 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
1193 // Init the communicate buffer. The buffer data size is:
1194 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
1196 PayloadSize
= sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
1197 Status
= InitCommunicateBuffer ((VOID
**)&SmmQueryVariableInfo
, PayloadSize
, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
);
1198 if (EFI_ERROR (Status
)) {
1201 ASSERT (SmmQueryVariableInfo
!= NULL
);
1203 SmmQueryVariableInfo
->Attributes
= Attributes
;
1206 // Send data to SMM.
1208 Status
= SendCommunicateBuffer (PayloadSize
);
1209 if (EFI_ERROR (Status
)) {
1214 // Get data from SMM.
1216 *MaximumVariableSize
= SmmQueryVariableInfo
->MaximumVariableSize
;
1217 *MaximumVariableStorageSize
= SmmQueryVariableInfo
->MaximumVariableStorageSize
;
1218 *RemainingVariableStorageSize
= SmmQueryVariableInfo
->RemainingVariableStorageSize
;
1221 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1227 Exit Boot Services Event notification handler.
1229 Notify SMM variable driver about the event.
1231 @param[in] Event Event whose notification function is being invoked.
1232 @param[in] Context Pointer to the notification function's context.
1237 OnExitBootServices (
1243 // Init the communicate buffer. The buffer data size is:
1244 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
1246 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
);
1249 // Send data to SMM.
1251 SendCommunicateBuffer (0);
1256 On Ready To Boot Services Event notification handler.
1258 Notify SMM variable driver about the event.
1260 @param[in] Event Event whose notification function is being invoked
1261 @param[in] Context Pointer to the notification function's context
1272 // Init the communicate buffer. The buffer data size is:
1273 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
1275 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT
);
1278 // Send data to SMM.
1280 SendCommunicateBuffer (0);
1283 // Install the system configuration table for variable info data captured
1285 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
) && FeaturePcdGet (PcdVariableCollectStatistics
)) {
1286 if (mVariableAuthFormat
) {
1287 gBS
->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid
, mVariableInfo
);
1289 gBS
->InstallConfigurationTable (&gEfiVariableGuid
, mVariableInfo
);
1293 gBS
->CloseEvent (Event
);
1298 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
1300 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1301 It convers pointer to new virtual address.
1303 @param[in] Event Event whose notification function is being invoked.
1304 @param[in] Context Pointer to the notification function's context.
1309 VariableAddressChangeEvent (
1314 EfiConvertPointer (0x0, (VOID
**) &mVariableBuffer
);
1315 EfiConvertPointer (0x0, (VOID
**) &mMmCommunication2
);
1316 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**) &mVariableRuntimeHobCacheBuffer
);
1317 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**) &mVariableRuntimeNvCacheBuffer
);
1318 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**) &mVariableRuntimeVolatileCacheBuffer
);
1322 This code gets variable payload size.
1324 @param[out] VariablePayloadSize Output pointer to variable payload size.
1326 @retval EFI_SUCCESS Get successfully.
1327 @retval Others Get unsuccessfully.
1332 GetVariablePayloadSize (
1333 OUT UINTN
*VariablePayloadSize
1337 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*SmmGetPayloadSize
;
1338 EFI_MM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1339 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1343 SmmGetPayloadSize
= NULL
;
1346 if(VariablePayloadSize
== NULL
) {
1347 return EFI_INVALID_PARAMETER
;
1350 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
1353 // Init the communicate buffer. The buffer data size is:
1354 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
1356 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
1357 CommBuffer
= AllocateZeroPool (CommSize
);
1358 if (CommBuffer
== NULL
) {
1359 Status
= EFI_OUT_OF_RESOURCES
;
1363 SmmCommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*) CommBuffer
;
1364 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1365 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
1367 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
1368 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE
;
1369 SmmGetPayloadSize
= (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*) SmmVariableFunctionHeader
->Data
;
1372 // Send data to SMM.
1374 Status
= mMmCommunication2
->Communicate (mMmCommunication2
, CommBuffer
, CommBuffer
, &CommSize
);
1375 ASSERT_EFI_ERROR (Status
);
1377 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1378 if (EFI_ERROR (Status
)) {
1383 // Get data from SMM.
1385 *VariablePayloadSize
= SmmGetPayloadSize
->VariablePayloadSize
;
1388 if (CommBuffer
!= NULL
) {
1389 FreePool (CommBuffer
);
1391 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1396 This code gets information needed from SMM for runtime cache initialization.
1398 @param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes.
1399 @param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes.
1400 @param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes.
1401 @param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used.
1403 @retval EFI_SUCCESS Retrieved the size successfully.
1404 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
1405 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
1406 @retval Others Could not retrieve the size successfully.
1410 GetRuntimeCacheInfo (
1411 OUT UINTN
*TotalHobStorageSize
,
1412 OUT UINTN
*TotalNvStorageSize
,
1413 OUT UINTN
*TotalVolatileStorageSize
,
1414 OUT BOOLEAN
*AuthenticatedVariableUsage
1418 SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
*SmmGetRuntimeCacheInfo
;
1419 EFI_MM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1420 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1424 SmmGetRuntimeCacheInfo
= NULL
;
1425 CommBuffer
= mVariableBuffer
;
1427 if (TotalHobStorageSize
== NULL
|| TotalNvStorageSize
== NULL
|| TotalVolatileStorageSize
== NULL
|| AuthenticatedVariableUsage
== NULL
) {
1428 return EFI_INVALID_PARAMETER
;
1431 if (CommBuffer
== NULL
) {
1432 return EFI_OUT_OF_RESOURCES
;
1435 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1437 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
);
1438 ZeroMem (CommBuffer
, CommSize
);
1440 SmmCommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*) CommBuffer
;
1441 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1442 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
);
1444 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
1445 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO
;
1446 SmmGetRuntimeCacheInfo
= (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
*) SmmVariableFunctionHeader
->Data
;
1449 // Send data to SMM.
1451 Status
= mMmCommunication2
->Communicate (mMmCommunication2
, CommBuffer
, CommBuffer
, &CommSize
);
1452 ASSERT_EFI_ERROR (Status
);
1453 if (CommSize
<= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
1454 Status
= EFI_BAD_BUFFER_SIZE
;
1458 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1459 if (EFI_ERROR (Status
)) {
1464 // Get data from SMM.
1466 *TotalHobStorageSize
= SmmGetRuntimeCacheInfo
->TotalHobStorageSize
;
1467 *TotalNvStorageSize
= SmmGetRuntimeCacheInfo
->TotalNvStorageSize
;
1468 *TotalVolatileStorageSize
= SmmGetRuntimeCacheInfo
->TotalVolatileStorageSize
;
1469 *AuthenticatedVariableUsage
= SmmGetRuntimeCacheInfo
->AuthenticatedVariableUsage
;
1472 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1477 Sends the runtime variable cache context information to SMM.
1479 @retval EFI_SUCCESS Retrieved the size successfully.
1480 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
1481 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
1482 @retval Others Could not retrieve the size successfully.;
1486 SendRuntimeVariableCacheContextToSmm (
1491 SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
*SmmRuntimeVarCacheContext
;
1492 EFI_MM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1493 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1497 SmmRuntimeVarCacheContext
= NULL
;
1498 CommBuffer
= mVariableBuffer
;
1500 if (CommBuffer
== NULL
) {
1501 return EFI_OUT_OF_RESOURCES
;
1504 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1507 // Init the communicate buffer. The buffer data size is:
1508 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
1510 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
);
1511 ZeroMem (CommBuffer
, CommSize
);
1513 SmmCommunicateHeader
= (EFI_MM_COMMUNICATE_HEADER
*) CommBuffer
;
1514 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1515 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
);
1517 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
1518 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT
;
1519 SmmRuntimeVarCacheContext
= (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
*) SmmVariableFunctionHeader
->Data
;
1521 SmmRuntimeVarCacheContext
->RuntimeHobCache
= mVariableRuntimeHobCacheBuffer
;
1522 SmmRuntimeVarCacheContext
->RuntimeVolatileCache
= mVariableRuntimeVolatileCacheBuffer
;
1523 SmmRuntimeVarCacheContext
->RuntimeNvCache
= mVariableRuntimeNvCacheBuffer
;
1524 SmmRuntimeVarCacheContext
->PendingUpdate
= &mVariableRuntimeCachePendingUpdate
;
1525 SmmRuntimeVarCacheContext
->ReadLock
= &mVariableRuntimeCacheReadLock
;
1526 SmmRuntimeVarCacheContext
->HobFlushComplete
= &mHobFlushComplete
;
1529 // Send data to SMM.
1531 Status
= mMmCommunication2
->Communicate (mMmCommunication2
, CommBuffer
, CommBuffer
, &CommSize
);
1532 ASSERT_EFI_ERROR (Status
);
1533 if (CommSize
<= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
1534 Status
= EFI_BAD_BUFFER_SIZE
;
1538 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1539 if (EFI_ERROR (Status
)) {
1544 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1549 Initialize variable service and install Variable Architectural protocol.
1551 @param[in] Event Event whose notification function is being invoked.
1552 @param[in] Context Pointer to the notification function's context.
1564 Status
= gBS
->LocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**) &mSmmVariable
);
1565 if (EFI_ERROR (Status
)) {
1569 Status
= gBS
->LocateProtocol (&gEfiMmCommunication2ProtocolGuid
, NULL
, (VOID
**) &mMmCommunication2
);
1570 ASSERT_EFI_ERROR (Status
);
1573 // Allocate memory for variable communicate buffer.
1575 Status
= GetVariablePayloadSize (&mVariableBufferPayloadSize
);
1576 ASSERT_EFI_ERROR (Status
);
1577 mVariableBufferSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ mVariableBufferPayloadSize
;
1578 mVariableBuffer
= AllocateRuntimePool (mVariableBufferSize
);
1579 ASSERT (mVariableBuffer
!= NULL
);
1582 // Save the buffer physical address used for SMM conmunication.
1584 mVariableBufferPhysical
= mVariableBuffer
;
1586 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
1587 DEBUG ((DEBUG_INFO
, "Variable driver runtime cache is enabled.\n"));
1589 // Allocate runtime variable cache memory buffers.
1591 Status
= GetRuntimeCacheInfo (
1592 &mVariableRuntimeHobCacheBufferSize
,
1593 &mVariableRuntimeNvCacheBufferSize
,
1594 &mVariableRuntimeVolatileCacheBufferSize
,
1595 &mVariableAuthFormat
1597 if (!EFI_ERROR (Status
)) {
1598 Status
= InitVariableCache (&mVariableRuntimeHobCacheBuffer
, &mVariableRuntimeHobCacheBufferSize
);
1599 if (!EFI_ERROR (Status
)) {
1600 Status
= InitVariableCache (&mVariableRuntimeNvCacheBuffer
, &mVariableRuntimeNvCacheBufferSize
);
1601 if (!EFI_ERROR (Status
)) {
1602 Status
= InitVariableCache (&mVariableRuntimeVolatileCacheBuffer
, &mVariableRuntimeVolatileCacheBufferSize
);
1603 if (!EFI_ERROR (Status
)) {
1604 Status
= SendRuntimeVariableCacheContextToSmm ();
1605 if (!EFI_ERROR (Status
)) {
1606 SyncRuntimeCache ();
1611 if (EFI_ERROR (Status
)) {
1612 mVariableRuntimeHobCacheBuffer
= NULL
;
1613 mVariableRuntimeNvCacheBuffer
= NULL
;
1614 mVariableRuntimeVolatileCacheBuffer
= NULL
;
1617 ASSERT_EFI_ERROR (Status
);
1619 DEBUG ((DEBUG_INFO
, "Variable driver runtime cache is disabled.\n"));
1622 gRT
->GetVariable
= RuntimeServiceGetVariable
;
1623 gRT
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
1624 gRT
->SetVariable
= RuntimeServiceSetVariable
;
1625 gRT
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
1628 // Install the Variable Architectural Protocol on a new handle.
1630 Status
= gBS
->InstallProtocolInterface (
1632 &gEfiVariableArchProtocolGuid
,
1633 EFI_NATIVE_INTERFACE
,
1636 ASSERT_EFI_ERROR (Status
);
1638 mVariableLock
.RequestToLock
= VariableLockRequestToLock
;
1639 Status
= gBS
->InstallMultipleProtocolInterfaces (
1641 &gEdkiiVariableLockProtocolGuid
,
1645 ASSERT_EFI_ERROR (Status
);
1647 mVarCheck
.RegisterSetVariableCheckHandler
= VarCheckRegisterSetVariableCheckHandler
;
1648 mVarCheck
.VariablePropertySet
= VarCheckVariablePropertySet
;
1649 mVarCheck
.VariablePropertyGet
= VarCheckVariablePropertyGet
;
1650 Status
= gBS
->InstallMultipleProtocolInterfaces (
1652 &gEdkiiVarCheckProtocolGuid
,
1656 ASSERT_EFI_ERROR (Status
);
1658 gBS
->CloseEvent (Event
);
1663 SMM Non-Volatile variable write service is ready notify event handler.
1665 @param[in] Event Event whose notification function is being invoked.
1666 @param[in] Context Pointer to the notification function's context.
1671 SmmVariableWriteReady (
1680 // Check whether the protocol is installed or not.
1682 Status
= gBS
->LocateProtocol (&gSmmVariableWriteGuid
, NULL
, (VOID
**) &ProtocolOps
);
1683 if (EFI_ERROR (Status
)) {
1688 // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
1689 // Secure Boot Policy Variable change. Record their initial value.
1691 RecordSecureBootPolicyVarData();
1693 Status
= gBS
->InstallProtocolInterface (
1695 &gEfiVariableWriteArchProtocolGuid
,
1696 EFI_NATIVE_INTERFACE
,
1699 ASSERT_EFI_ERROR (Status
);
1701 gBS
->CloseEvent (Event
);
1706 Variable Driver main entry point. The Variable driver places the 4 EFI
1707 runtime services in the EFI System Table and installs arch protocols
1708 for variable read and write services being available. It also registers
1709 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1711 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1712 @param[in] SystemTable A pointer to the EFI System Table.
1714 @retval EFI_SUCCESS Variable service successfully initialized.
1719 VariableSmmRuntimeInitialize (
1720 IN EFI_HANDLE ImageHandle
,
1721 IN EFI_SYSTEM_TABLE
*SystemTable
1724 VOID
*SmmVariableRegistration
;
1725 VOID
*SmmVariableWriteRegistration
;
1726 EFI_EVENT OnReadyToBootEvent
;
1727 EFI_EVENT ExitBootServiceEvent
;
1728 EFI_EVENT LegacyBootEvent
;
1730 EfiInitializeLock (&mVariableServicesLock
, TPL_NOTIFY
);
1733 // Smm variable service is ready
1735 EfiCreateProtocolNotifyEvent (
1736 &gEfiSmmVariableProtocolGuid
,
1740 &SmmVariableRegistration
1744 // Smm Non-Volatile variable write service is ready
1746 EfiCreateProtocolNotifyEvent (
1747 &gSmmVariableWriteGuid
,
1749 SmmVariableWriteReady
,
1751 &SmmVariableWriteRegistration
1755 // Register the event to reclaim variable for OS usage.
1757 EfiCreateEventReadyToBootEx (
1765 // Register the event to inform SMM variable that it is at runtime.
1767 gBS
->CreateEventEx (
1772 &gEfiEventExitBootServicesGuid
,
1773 &ExitBootServiceEvent
1777 // Register the event to inform SMM variable that it is at runtime for legacy boot.
1778 // Reuse OnExitBootServices() here.
1780 EfiCreateEventLegacyBootEx(
1788 // Register the event to convert the pointer for runtime.
1790 gBS
->CreateEventEx (
1793 VariableAddressChangeEvent
,
1795 &gEfiEventVirtualAddressChangeGuid
,
1796 &mVirtualAddressChangeEvent