2 Implement all four UEFI Runtime Variable services for the nonvolatile
3 and volatile storage space and install variable architecture protocol
4 based on SMM variable module.
6 Caution: This module requires additional review when modified.
7 This driver will have external input - variable data.
8 This external input must be validated carefully to avoid security issue like
9 buffer overflow, integer overflow.
11 RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
12 to receive data buffer. The size should be checked carefully.
14 InitCommunicateBuffer() is really function to check the variable data size.
16 Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
17 SPDX-License-Identifier: BSD-2-Clause-Patent
21 #include <Protocol/VariableWrite.h>
22 #include <Protocol/Variable.h>
23 #include <Protocol/SmmCommunication.h>
24 #include <Protocol/SmmVariable.h>
25 #include <Protocol/VariableLock.h>
26 #include <Protocol/VarCheck.h>
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Library/MemoryAllocationLib.h>
31 #include <Library/UefiDriverEntryPoint.h>
32 #include <Library/UefiRuntimeLib.h>
33 #include <Library/BaseMemoryLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/UefiLib.h>
36 #include <Library/BaseLib.h>
38 #include <Guid/EventGroup.h>
39 #include <Guid/SmmVariableCommon.h>
41 #include "PrivilegePolymorphic.h"
42 #include "VariableParsing.h"
44 EFI_HANDLE mHandle
= NULL
;
45 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
= NULL
;
46 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
47 EFI_SMM_COMMUNICATION_PROTOCOL
*mSmmCommunication
= NULL
;
48 UINT8
*mVariableBuffer
= NULL
;
49 UINT8
*mVariableBufferPhysical
= NULL
;
50 VARIABLE_INFO_ENTRY
*mVariableInfo
= NULL
;
51 VARIABLE_STORE_HEADER
*mVariableRuntimeHobCacheBuffer
= NULL
;
52 VARIABLE_STORE_HEADER
*mVariableRuntimeNvCacheBuffer
= NULL
;
53 VARIABLE_STORE_HEADER
*mVariableRuntimeVolatileCacheBuffer
= NULL
;
54 UINTN mVariableBufferSize
;
55 UINTN mVariableRuntimeHobCacheBufferSize
;
56 UINTN mVariableRuntimeNvCacheBufferSize
;
57 UINTN mVariableRuntimeVolatileCacheBufferSize
;
58 UINTN mVariableBufferPayloadSize
;
59 BOOLEAN mVariableRuntimeCachePendingUpdate
;
60 BOOLEAN mVariableRuntimeCacheReadLock
;
61 BOOLEAN mVariableAuthFormat
;
62 BOOLEAN mHobFlushComplete
;
63 EFI_LOCK mVariableServicesLock
;
64 EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock
;
65 EDKII_VAR_CHECK_PROTOCOL mVarCheck
;
68 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
69 Record their initial State when variable write service is ready.
74 RecordSecureBootPolicyVarData(
79 Acquires lock only at boot time. Simply returns at runtime.
81 This is a temperary function that will be removed when
82 EfiAcquireLock() in UefiLib can handle the call in UEFI
83 Runtimer driver in RT phase.
84 It calls EfiAcquireLock() at boot time, and simply returns
87 @param Lock A pointer to the lock to acquire.
91 AcquireLockOnlyAtBootTime (
95 if (!EfiAtRuntime ()) {
96 EfiAcquireLock (Lock
);
101 Releases lock only at boot time. Simply returns at runtime.
103 This is a temperary function which will be removed when
104 EfiReleaseLock() in UefiLib can handle the call in UEFI
105 Runtimer driver in RT phase.
106 It calls EfiReleaseLock() at boot time and simply returns
109 @param Lock A pointer to the lock to release.
113 ReleaseLockOnlyAtBootTime (
117 if (!EfiAtRuntime ()) {
118 EfiReleaseLock (Lock
);
123 Return TRUE if ExitBootServices () has been called.
125 @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.
132 return EfiAtRuntime ();
136 Initialize the variable cache buffer as an empty variable store.
138 @param[out] VariableCacheBuffer A pointer to pointer of a cache variable store.
139 @param[in,out] TotalVariableCacheSize On input, the minimum size needed for the UEFI variable store cache
140 buffer that is allocated. On output, the actual size of the buffer allocated.
141 If TotalVariableCacheSize is zero, a buffer will not be allocated and the
142 function will return with EFI_SUCCESS.
144 @retval EFI_SUCCESS The variable cache was allocated and initialized successfully.
145 @retval EFI_INVALID_PARAMETER A given pointer is NULL or an invalid variable store size was specified.
146 @retval EFI_OUT_OF_RESOURCES Insufficient resources are available to allocate the variable store cache buffer.
151 OUT VARIABLE_STORE_HEADER
**VariableCacheBuffer
,
152 IN OUT UINTN
*TotalVariableCacheSize
155 VARIABLE_STORE_HEADER
*VariableCacheStorePtr
;
157 if (TotalVariableCacheSize
== NULL
) {
158 return EFI_INVALID_PARAMETER
;
160 if (*TotalVariableCacheSize
== 0) {
163 if (VariableCacheBuffer
== NULL
|| *TotalVariableCacheSize
< sizeof (VARIABLE_STORE_HEADER
)) {
164 return EFI_INVALID_PARAMETER
;
166 *TotalVariableCacheSize
= ALIGN_VALUE (*TotalVariableCacheSize
, sizeof (UINT32
));
169 // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)
171 *VariableCacheBuffer
= (VARIABLE_STORE_HEADER
*) AllocateRuntimePages (
172 EFI_SIZE_TO_PAGES (*TotalVariableCacheSize
)
174 if (*VariableCacheBuffer
== NULL
) {
175 return EFI_OUT_OF_RESOURCES
;
177 VariableCacheStorePtr
= *VariableCacheBuffer
;
178 SetMem32 ((VOID
*) VariableCacheStorePtr
, *TotalVariableCacheSize
, (UINT32
) 0xFFFFFFFF);
180 ZeroMem ((VOID
*) VariableCacheStorePtr
, sizeof (VARIABLE_STORE_HEADER
));
181 VariableCacheStorePtr
->Size
= (UINT32
) *TotalVariableCacheSize
;
182 VariableCacheStorePtr
->Format
= VARIABLE_STORE_FORMATTED
;
183 VariableCacheStorePtr
->State
= VARIABLE_STORE_HEALTHY
;
189 Initialize the communicate buffer using DataSize and Function.
191 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
194 Caution: This function may receive untrusted input.
195 The data size external input, so this function will validate it carefully to avoid buffer overflow.
197 @param[out] DataPtr Points to the data in the communicate buffer.
198 @param[in] DataSize The data size to send to SMM.
199 @param[in] Function The function number to initialize the communicate header.
201 @retval EFI_INVALID_PARAMETER The data size is too big.
202 @retval EFI_SUCCESS Find the specified variable.
206 InitCommunicateBuffer (
207 OUT VOID
**DataPtr OPTIONAL
,
212 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
213 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
216 if (DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
> mVariableBufferSize
) {
217 return EFI_INVALID_PARAMETER
;
220 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
221 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
222 SmmCommunicateHeader
->MessageLength
= DataSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
224 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
225 SmmVariableFunctionHeader
->Function
= Function
;
226 if (DataPtr
!= NULL
) {
227 *DataPtr
= SmmVariableFunctionHeader
->Data
;
235 Send the data in communicate buffer to SMM.
237 @param[in] DataSize This size of the function header and the data.
239 @retval EFI_SUCCESS Success is returned from the functin in SMM.
240 @retval Others Failure is returned from the function in SMM.
244 SendCommunicateBuffer (
250 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
251 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
253 CommSize
= DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
254 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, mVariableBufferPhysical
, &CommSize
);
255 ASSERT_EFI_ERROR (Status
);
257 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
258 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
259 return SmmVariableFunctionHeader
->ReturnStatus
;
263 Mark a variable that will become read-only after leaving the DXE phase of execution.
265 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
266 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
267 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
269 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
270 as pending to be read-only.
271 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
272 Or VariableName is an empty string.
273 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
274 already been signaled.
275 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
279 VariableLockRequestToLock (
280 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
281 IN CHAR16
*VariableName
,
282 IN EFI_GUID
*VendorGuid
286 UINTN VariableNameSize
;
288 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
290 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
291 return EFI_INVALID_PARAMETER
;
294 VariableNameSize
= StrSize (VariableName
);
295 VariableToLock
= NULL
;
298 // If VariableName exceeds SMM payload limit. Return failure
300 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
)) {
301 return EFI_INVALID_PARAMETER
;
304 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
307 // Init the communicate buffer. The buffer data size is:
308 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
310 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
) + VariableNameSize
;
311 Status
= InitCommunicateBuffer ((VOID
**) &VariableToLock
, PayloadSize
, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
);
312 if (EFI_ERROR (Status
)) {
315 ASSERT (VariableToLock
!= NULL
);
317 CopyGuid (&VariableToLock
->Guid
, VendorGuid
);
318 VariableToLock
->NameSize
= VariableNameSize
;
319 CopyMem (VariableToLock
->Name
, VariableName
, VariableToLock
->NameSize
);
324 Status
= SendCommunicateBuffer (PayloadSize
);
327 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
332 Register SetVariable check handler.
334 @param[in] Handler Pointer to check handler.
336 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
337 @retval EFI_INVALID_PARAMETER Handler is NULL.
338 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
339 already been signaled.
340 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
341 @retval EFI_UNSUPPORTED This interface is not implemented.
342 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
347 VarCheckRegisterSetVariableCheckHandler (
348 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
351 return EFI_UNSUPPORTED
;
355 Variable property set.
357 @param[in] Name Pointer to the variable name.
358 @param[in] Guid Pointer to the vendor GUID.
359 @param[in] VariableProperty Pointer to the input variable property.
361 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
362 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
363 or the fields of VariableProperty are not valid.
364 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
365 already been signaled.
366 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
371 VarCheckVariablePropertySet (
374 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
378 UINTN VariableNameSize
;
380 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
382 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
383 return EFI_INVALID_PARAMETER
;
386 if (VariableProperty
== NULL
) {
387 return EFI_INVALID_PARAMETER
;
390 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
391 return EFI_INVALID_PARAMETER
;
394 VariableNameSize
= StrSize (Name
);
395 CommVariableProperty
= NULL
;
398 // If VariableName exceeds SMM payload limit. Return failure
400 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
401 return EFI_INVALID_PARAMETER
;
404 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
407 // Init the communicate buffer. The buffer data size is:
408 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
410 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
411 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
);
412 if (EFI_ERROR (Status
)) {
415 ASSERT (CommVariableProperty
!= NULL
);
417 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
418 CopyMem (&CommVariableProperty
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
419 CommVariableProperty
->NameSize
= VariableNameSize
;
420 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
425 Status
= SendCommunicateBuffer (PayloadSize
);
428 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
433 Variable property get.
435 @param[in] Name Pointer to the variable name.
436 @param[in] Guid Pointer to the vendor GUID.
437 @param[out] VariableProperty Pointer to the output variable property.
439 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
440 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
441 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
446 VarCheckVariablePropertyGet (
449 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
453 UINTN VariableNameSize
;
455 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
457 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
458 return EFI_INVALID_PARAMETER
;
461 if (VariableProperty
== NULL
) {
462 return EFI_INVALID_PARAMETER
;
465 VariableNameSize
= StrSize (Name
);
466 CommVariableProperty
= NULL
;
469 // If VariableName exceeds SMM payload limit. Return failure
471 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
472 return EFI_INVALID_PARAMETER
;
475 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
478 // Init the communicate buffer. The buffer data size is:
479 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
481 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
482 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
);
483 if (EFI_ERROR (Status
)) {
486 ASSERT (CommVariableProperty
!= NULL
);
488 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
489 CommVariableProperty
->NameSize
= VariableNameSize
;
490 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
495 Status
= SendCommunicateBuffer (PayloadSize
);
496 if (Status
== EFI_SUCCESS
) {
497 CopyMem (VariableProperty
, &CommVariableProperty
->VariableProperty
, sizeof (*VariableProperty
));
501 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
506 Signals SMM to synchronize any pending variable updates with the runtime cache(s).
515 // Init the communicate buffer. The buffer data size is:
516 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
518 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE
);
523 SendCommunicateBuffer (0);
527 Check whether a SMI must be triggered to retrieve pending cache updates.
529 If the variable HOB was finished being flushed since the last check for a runtime cache update, this function
530 will prevent the HOB cache from being used for future runtime cache hits.
534 CheckForRuntimeCacheSync (
538 if (mVariableRuntimeCachePendingUpdate
) {
541 ASSERT (!mVariableRuntimeCachePendingUpdate
);
544 // The HOB variable data may have finished being flushed in the runtime cache sync update
546 if (mHobFlushComplete
&& mVariableRuntimeHobCacheBuffer
!= NULL
) {
547 if (!EfiAtRuntime ()) {
548 FreePages (mVariableRuntimeHobCacheBuffer
, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize
));
550 mVariableRuntimeHobCacheBuffer
= NULL
;
555 Finds the given variable in a runtime cache variable store.
557 Caution: This function may receive untrusted input.
558 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
560 @param[in] VariableName Name of Variable to be found.
561 @param[in] VendorGuid Variable vendor GUID.
562 @param[out] Attributes Attribute value of the variable found.
563 @param[in, out] DataSize Size of Data found. If size is less than the
564 data, this value contains the required size.
565 @param[out] Data Data pointer.
567 @retval EFI_SUCCESS Found the specified variable.
568 @retval EFI_INVALID_PARAMETER Invalid parameter.
569 @retval EFI_NOT_FOUND The specified variable could not be found.
573 FindVariableInRuntimeCache (
574 IN CHAR16
*VariableName
,
575 IN EFI_GUID
*VendorGuid
,
576 OUT UINT32
*Attributes OPTIONAL
,
577 IN OUT UINTN
*DataSize
,
578 OUT VOID
*Data OPTIONAL
583 VARIABLE_POINTER_TRACK RtPtrTrack
;
584 VARIABLE_STORE_TYPE StoreType
;
585 VARIABLE_STORE_HEADER
*VariableStoreList
[VariableStoreTypeMax
];
587 Status
= EFI_NOT_FOUND
;
589 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
590 return EFI_INVALID_PARAMETER
;
594 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
595 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
596 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
597 // cache read lock should always be free when entering this function.
599 ASSERT (!mVariableRuntimeCacheReadLock
);
601 mVariableRuntimeCacheReadLock
= TRUE
;
602 CheckForRuntimeCacheSync ();
604 if (!mVariableRuntimeCachePendingUpdate
) {
606 // 0: Volatile, 1: HOB, 2: Non-Volatile.
607 // The index and attributes mapping must be kept in this order as FindVariable
608 // makes use of this mapping to implement search algorithm.
610 VariableStoreList
[VariableStoreTypeVolatile
] = mVariableRuntimeVolatileCacheBuffer
;
611 VariableStoreList
[VariableStoreTypeHob
] = mVariableRuntimeHobCacheBuffer
;
612 VariableStoreList
[VariableStoreTypeNv
] = mVariableRuntimeNvCacheBuffer
;
614 for (StoreType
= (VARIABLE_STORE_TYPE
) 0; StoreType
< VariableStoreTypeMax
; StoreType
++) {
615 if (VariableStoreList
[StoreType
] == NULL
) {
619 RtPtrTrack
.StartPtr
= GetStartPointer (VariableStoreList
[StoreType
]);
620 RtPtrTrack
.EndPtr
= GetEndPointer (VariableStoreList
[StoreType
]);
621 RtPtrTrack
.Volatile
= (BOOLEAN
) (StoreType
== VariableStoreTypeVolatile
);
623 Status
= FindVariableEx (VariableName
, VendorGuid
, FALSE
, &RtPtrTrack
, mVariableAuthFormat
);
624 if (!EFI_ERROR (Status
)) {
629 if (!EFI_ERROR (Status
)) {
633 TempDataSize
= DataSizeOfVariable (RtPtrTrack
.CurrPtr
, mVariableAuthFormat
);
634 ASSERT (TempDataSize
!= 0);
636 if (*DataSize
>= TempDataSize
) {
638 Status
= EFI_INVALID_PARAMETER
;
642 CopyMem (Data
, GetVariableDataPtr (RtPtrTrack
.CurrPtr
, mVariableAuthFormat
), TempDataSize
);
643 if (Attributes
!= NULL
) {
644 *Attributes
= RtPtrTrack
.CurrPtr
->Attributes
;
647 *DataSize
= TempDataSize
;
649 UpdateVariableInfo (VariableName
, VendorGuid
, RtPtrTrack
.Volatile
, TRUE
, FALSE
, FALSE
, TRUE
, &mVariableInfo
);
651 Status
= EFI_SUCCESS
;
654 *DataSize
= TempDataSize
;
655 Status
= EFI_BUFFER_TOO_SMALL
;
662 mVariableRuntimeCacheReadLock
= FALSE
;
668 Finds the given variable in a variable store in SMM.
670 Caution: This function may receive untrusted input.
671 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
673 @param[in] VariableName Name of Variable to be found.
674 @param[in] VendorGuid Variable vendor GUID.
675 @param[out] Attributes Attribute value of the variable found.
676 @param[in, out] DataSize Size of Data found. If size is less than the
677 data, this value contains the required size.
678 @param[out] Data Data pointer.
680 @retval EFI_SUCCESS Found the specified variable.
681 @retval EFI_INVALID_PARAMETER Invalid parameter.
682 @retval EFI_NOT_FOUND The specified variable could not be found.
687 IN CHAR16
*VariableName
,
688 IN EFI_GUID
*VendorGuid
,
689 OUT UINT32
*Attributes OPTIONAL
,
690 IN OUT UINTN
*DataSize
,
691 OUT VOID
*Data OPTIONAL
696 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
698 UINTN VariableNameSize
;
700 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
701 return EFI_INVALID_PARAMETER
;
704 TempDataSize
= *DataSize
;
705 VariableNameSize
= StrSize (VariableName
);
706 SmmVariableHeader
= NULL
;
709 // If VariableName exceeds SMM payload limit. Return failure
711 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
712 return EFI_INVALID_PARAMETER
;
716 // Init the communicate buffer. The buffer data size is:
717 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
719 if (TempDataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
) {
721 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
723 TempDataSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
;
725 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ TempDataSize
;
727 Status
= InitCommunicateBuffer ((VOID
**) &SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_VARIABLE
);
728 if (EFI_ERROR (Status
)) {
731 ASSERT (SmmVariableHeader
!= NULL
);
733 CopyGuid (&SmmVariableHeader
->Guid
, VendorGuid
);
734 SmmVariableHeader
->DataSize
= TempDataSize
;
735 SmmVariableHeader
->NameSize
= VariableNameSize
;
736 if (Attributes
== NULL
) {
737 SmmVariableHeader
->Attributes
= 0;
739 SmmVariableHeader
->Attributes
= *Attributes
;
741 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
746 Status
= SendCommunicateBuffer (PayloadSize
);
749 // Get data from SMM.
751 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
753 // SMM CommBuffer DataSize can be a trimed value
754 // Only update DataSize when needed
756 *DataSize
= SmmVariableHeader
->DataSize
;
758 if (Attributes
!= NULL
) {
759 *Attributes
= SmmVariableHeader
->Attributes
;
762 if (EFI_ERROR (Status
)) {
767 CopyMem (Data
, (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, SmmVariableHeader
->DataSize
);
769 Status
= EFI_INVALID_PARAMETER
;
777 This code finds variable in storage blocks (Volatile or Non-Volatile).
779 Caution: This function may receive untrusted input.
780 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
782 @param[in] VariableName Name of Variable to be found.
783 @param[in] VendorGuid Variable vendor GUID.
784 @param[out] Attributes Attribute value of the variable found.
785 @param[in, out] DataSize Size of Data found. If size is less than the
786 data, this value contains the required size.
787 @param[out] Data Data pointer.
789 @retval EFI_INVALID_PARAMETER Invalid parameter.
790 @retval EFI_SUCCESS Find the specified variable.
791 @retval EFI_NOT_FOUND Not found.
792 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
797 RuntimeServiceGetVariable (
798 IN CHAR16
*VariableName
,
799 IN EFI_GUID
*VendorGuid
,
800 OUT UINT32
*Attributes OPTIONAL
,
801 IN OUT UINTN
*DataSize
,
807 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
808 return EFI_INVALID_PARAMETER
;
810 if (VariableName
[0] == 0) {
811 return EFI_NOT_FOUND
;
814 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
815 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
816 Status
= FindVariableInRuntimeCache (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
818 Status
= FindVariableInSmm (VariableName
, VendorGuid
, Attributes
, DataSize
, Data
);
820 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
826 Finds the next available variable in a runtime cache variable store.
828 @param[in, out] VariableNameSize Size of the variable name.
829 @param[in, out] VariableName Pointer to variable name.
830 @param[in, out] VendorGuid Variable Vendor Guid.
832 @retval EFI_INVALID_PARAMETER Invalid parameter.
833 @retval EFI_SUCCESS Find the specified variable.
834 @retval EFI_NOT_FOUND Not found.
835 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
839 GetNextVariableNameInRuntimeCache (
840 IN OUT UINTN
*VariableNameSize
,
841 IN OUT CHAR16
*VariableName
,
842 IN OUT EFI_GUID
*VendorGuid
847 VARIABLE_HEADER
*VariablePtr
;
848 VARIABLE_STORE_HEADER
*VariableStoreHeader
[VariableStoreTypeMax
];
850 Status
= EFI_NOT_FOUND
;
853 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service
854 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent
855 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime
856 // cache read lock should always be free when entering this function.
858 ASSERT (!mVariableRuntimeCacheReadLock
);
860 CheckForRuntimeCacheSync ();
862 mVariableRuntimeCacheReadLock
= TRUE
;
863 if (!mVariableRuntimeCachePendingUpdate
) {
865 // 0: Volatile, 1: HOB, 2: Non-Volatile.
866 // The index and attributes mapping must be kept in this order as FindVariable
867 // makes use of this mapping to implement search algorithm.
869 VariableStoreHeader
[VariableStoreTypeVolatile
] = mVariableRuntimeVolatileCacheBuffer
;
870 VariableStoreHeader
[VariableStoreTypeHob
] = mVariableRuntimeHobCacheBuffer
;
871 VariableStoreHeader
[VariableStoreTypeNv
] = mVariableRuntimeNvCacheBuffer
;
873 Status
= VariableServiceGetNextVariableInternal (
880 if (!EFI_ERROR (Status
)) {
881 VarNameSize
= NameSizeOfVariable (VariablePtr
, mVariableAuthFormat
);
882 ASSERT (VarNameSize
!= 0);
883 if (VarNameSize
<= *VariableNameSize
) {
884 CopyMem (VariableName
, GetVariableNamePtr (VariablePtr
, mVariableAuthFormat
), VarNameSize
);
885 CopyMem (VendorGuid
, GetVendorGuidPtr (VariablePtr
, mVariableAuthFormat
), sizeof (EFI_GUID
));
886 Status
= EFI_SUCCESS
;
888 Status
= EFI_BUFFER_TOO_SMALL
;
891 *VariableNameSize
= VarNameSize
;
894 mVariableRuntimeCacheReadLock
= FALSE
;
900 Finds the next available variable in a SMM variable store.
902 @param[in, out] VariableNameSize Size of the variable name.
903 @param[in, out] VariableName Pointer to variable name.
904 @param[in, out] VendorGuid Variable Vendor Guid.
906 @retval EFI_INVALID_PARAMETER Invalid parameter.
907 @retval EFI_SUCCESS Find the specified variable.
908 @retval EFI_NOT_FOUND Not found.
909 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
913 GetNextVariableNameInSmm (
914 IN OUT UINTN
*VariableNameSize
,
915 IN OUT CHAR16
*VariableName
,
916 IN OUT EFI_GUID
*VendorGuid
921 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*SmmGetNextVariableName
;
922 UINTN OutVariableNameSize
;
923 UINTN InVariableNameSize
;
925 OutVariableNameSize
= *VariableNameSize
;
926 InVariableNameSize
= StrSize (VariableName
);
927 SmmGetNextVariableName
= NULL
;
930 // If input string exceeds SMM payload limit. Return failure
932 if (InVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
933 return EFI_INVALID_PARAMETER
;
937 // Init the communicate buffer. The buffer data size is:
938 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
940 if (OutVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
942 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
944 OutVariableNameSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
947 // Payload should be Guid + NameSize + MAX of Input & Output buffer
949 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + MAX (OutVariableNameSize
, InVariableNameSize
);
951 Status
= InitCommunicateBuffer ((VOID
**)&SmmGetNextVariableName
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
);
952 if (EFI_ERROR (Status
)) {
955 ASSERT (SmmGetNextVariableName
!= NULL
);
958 // SMM comm buffer->NameSize is buffer size for return string
960 SmmGetNextVariableName
->NameSize
= OutVariableNameSize
;
962 CopyGuid (&SmmGetNextVariableName
->Guid
, VendorGuid
);
966 CopyMem (SmmGetNextVariableName
->Name
, VariableName
, InVariableNameSize
);
967 if (OutVariableNameSize
> InVariableNameSize
) {
968 ZeroMem ((UINT8
*) SmmGetNextVariableName
->Name
+ InVariableNameSize
, OutVariableNameSize
- InVariableNameSize
);
974 Status
= SendCommunicateBuffer (PayloadSize
);
977 // Get data from SMM.
979 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
981 // SMM CommBuffer NameSize can be a trimed value
982 // Only update VariableNameSize when needed
984 *VariableNameSize
= SmmGetNextVariableName
->NameSize
;
986 if (EFI_ERROR (Status
)) {
990 CopyGuid (VendorGuid
, &SmmGetNextVariableName
->Guid
);
991 CopyMem (VariableName
, SmmGetNextVariableName
->Name
, SmmGetNextVariableName
->NameSize
);
998 This code Finds the Next available variable.
1000 @param[in, out] VariableNameSize Size of the variable name.
1001 @param[in, out] VariableName Pointer to variable name.
1002 @param[in, out] VendorGuid Variable Vendor Guid.
1004 @retval EFI_INVALID_PARAMETER Invalid parameter.
1005 @retval EFI_SUCCESS Find the specified variable.
1006 @retval EFI_NOT_FOUND Not found.
1007 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
1012 RuntimeServiceGetNextVariableName (
1013 IN OUT UINTN
*VariableNameSize
,
1014 IN OUT CHAR16
*VariableName
,
1015 IN OUT EFI_GUID
*VendorGuid
1021 Status
= EFI_NOT_FOUND
;
1023 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
1024 return EFI_INVALID_PARAMETER
;
1028 // Calculate the possible maximum length of name string, including the Null terminator.
1030 MaxLen
= *VariableNameSize
/ sizeof (CHAR16
);
1031 if ((MaxLen
== 0) || (StrnLenS (VariableName
, MaxLen
) == MaxLen
)) {
1033 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
1034 // follow spec to return EFI_INVALID_PARAMETER.
1036 return EFI_INVALID_PARAMETER
;
1039 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1040 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
1041 Status
= GetNextVariableNameInRuntimeCache (VariableNameSize
, VariableName
, VendorGuid
);
1043 Status
= GetNextVariableNameInSmm (VariableNameSize
, VariableName
, VendorGuid
);
1045 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1051 This code sets variable in storage blocks (Volatile or Non-Volatile).
1053 Caution: This function may receive untrusted input.
1054 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
1056 @param[in] VariableName Name of Variable to be found.
1057 @param[in] VendorGuid Variable vendor GUID.
1058 @param[in] Attributes Attribute value of the variable found
1059 @param[in] DataSize Size of Data found. If size is less than the
1060 data, this value contains the required size.
1061 @param[in] Data Data pointer.
1063 @retval EFI_INVALID_PARAMETER Invalid parameter.
1064 @retval EFI_SUCCESS Set successfully.
1065 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
1066 @retval EFI_NOT_FOUND Not found.
1067 @retval EFI_WRITE_PROTECTED Variable is read-only.
1072 RuntimeServiceSetVariable (
1073 IN CHAR16
*VariableName
,
1074 IN EFI_GUID
*VendorGuid
,
1075 IN UINT32 Attributes
,
1082 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
1083 UINTN VariableNameSize
;
1086 // Check input parameters.
1088 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
1089 return EFI_INVALID_PARAMETER
;
1092 if (DataSize
!= 0 && Data
== NULL
) {
1093 return EFI_INVALID_PARAMETER
;
1096 VariableNameSize
= StrSize (VariableName
);
1097 SmmVariableHeader
= NULL
;
1100 // If VariableName or DataSize exceeds SMM payload limit. Return failure
1102 if ((VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
1103 (DataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
)){
1104 return EFI_INVALID_PARAMETER
;
1107 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
1110 // Init the communicate buffer. The buffer data size is:
1111 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
1113 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ DataSize
;
1114 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_SET_VARIABLE
);
1115 if (EFI_ERROR (Status
)) {
1118 ASSERT (SmmVariableHeader
!= NULL
);
1120 CopyGuid ((EFI_GUID
*) &SmmVariableHeader
->Guid
, VendorGuid
);
1121 SmmVariableHeader
->DataSize
= DataSize
;
1122 SmmVariableHeader
->NameSize
= VariableNameSize
;
1123 SmmVariableHeader
->Attributes
= Attributes
;
1124 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
1125 CopyMem ((UINT8
*) SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, Data
, DataSize
);
1128 // Send data to SMM.
1130 Status
= SendCommunicateBuffer (PayloadSize
);
1133 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1135 if (!EfiAtRuntime ()) {
1136 if (!EFI_ERROR (Status
)) {
1148 This code returns information about the EFI variables.
1150 @param[in] Attributes Attributes bitmask to specify the type of variables
1151 on which to return information.
1152 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
1153 for the EFI variables associated with the attributes specified.
1154 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
1155 for EFI variables associated with the attributes specified.
1156 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
1157 associated with the attributes specified.
1159 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
1160 @retval EFI_SUCCESS Query successfully.
1161 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
1166 RuntimeServiceQueryVariableInfo (
1167 IN UINT32 Attributes
,
1168 OUT UINT64
*MaximumVariableStorageSize
,
1169 OUT UINT64
*RemainingVariableStorageSize
,
1170 OUT UINT64
*MaximumVariableSize
1175 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*SmmQueryVariableInfo
;
1177 SmmQueryVariableInfo
= NULL
;
1179 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
1180 return EFI_INVALID_PARAMETER
;
1183 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
1186 // Init the communicate buffer. The buffer data size is:
1187 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
1189 PayloadSize
= sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
1190 Status
= InitCommunicateBuffer ((VOID
**)&SmmQueryVariableInfo
, PayloadSize
, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
);
1191 if (EFI_ERROR (Status
)) {
1194 ASSERT (SmmQueryVariableInfo
!= NULL
);
1196 SmmQueryVariableInfo
->Attributes
= Attributes
;
1199 // Send data to SMM.
1201 Status
= SendCommunicateBuffer (PayloadSize
);
1202 if (EFI_ERROR (Status
)) {
1207 // Get data from SMM.
1209 *MaximumVariableSize
= SmmQueryVariableInfo
->MaximumVariableSize
;
1210 *MaximumVariableStorageSize
= SmmQueryVariableInfo
->MaximumVariableStorageSize
;
1211 *RemainingVariableStorageSize
= SmmQueryVariableInfo
->RemainingVariableStorageSize
;
1214 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1220 Exit Boot Services Event notification handler.
1222 Notify SMM variable driver about the event.
1224 @param[in] Event Event whose notification function is being invoked.
1225 @param[in] Context Pointer to the notification function's context.
1230 OnExitBootServices (
1236 // Init the communicate buffer. The buffer data size is:
1237 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
1239 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
);
1242 // Send data to SMM.
1244 SendCommunicateBuffer (0);
1249 On Ready To Boot Services Event notification handler.
1251 Notify SMM variable driver about the event.
1253 @param[in] Event Event whose notification function is being invoked
1254 @param[in] Context Pointer to the notification function's context
1265 // Init the communicate buffer. The buffer data size is:
1266 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
1268 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT
);
1271 // Send data to SMM.
1273 SendCommunicateBuffer (0);
1276 // Install the system configuration table for variable info data captured
1278 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
) && FeaturePcdGet (PcdVariableCollectStatistics
)) {
1279 if (mVariableAuthFormat
) {
1280 gBS
->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid
, mVariableInfo
);
1282 gBS
->InstallConfigurationTable (&gEfiVariableGuid
, mVariableInfo
);
1286 gBS
->CloseEvent (Event
);
1291 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
1293 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1294 It convers pointer to new virtual address.
1296 @param[in] Event Event whose notification function is being invoked.
1297 @param[in] Context Pointer to the notification function's context.
1302 VariableAddressChangeEvent (
1307 EfiConvertPointer (0x0, (VOID
**) &mVariableBuffer
);
1308 EfiConvertPointer (0x0, (VOID
**) &mSmmCommunication
);
1309 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**) &mVariableRuntimeHobCacheBuffer
);
1310 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**) &mVariableRuntimeNvCacheBuffer
);
1311 EfiConvertPointer (EFI_OPTIONAL_PTR
, (VOID
**) &mVariableRuntimeVolatileCacheBuffer
);
1315 This code gets variable payload size.
1317 @param[out] VariablePayloadSize Output pointer to variable payload size.
1319 @retval EFI_SUCCESS Get successfully.
1320 @retval Others Get unsuccessfully.
1325 GetVariablePayloadSize (
1326 OUT UINTN
*VariablePayloadSize
1330 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*SmmGetPayloadSize
;
1331 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1332 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1336 SmmGetPayloadSize
= NULL
;
1339 if(VariablePayloadSize
== NULL
) {
1340 return EFI_INVALID_PARAMETER
;
1343 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
1346 // Init the communicate buffer. The buffer data size is:
1347 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
1349 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
1350 CommBuffer
= AllocateZeroPool (CommSize
);
1351 if (CommBuffer
== NULL
) {
1352 Status
= EFI_OUT_OF_RESOURCES
;
1356 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) CommBuffer
;
1357 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1358 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
1360 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
1361 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE
;
1362 SmmGetPayloadSize
= (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*) SmmVariableFunctionHeader
->Data
;
1365 // Send data to SMM.
1367 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, CommBuffer
, &CommSize
);
1368 ASSERT_EFI_ERROR (Status
);
1370 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1371 if (EFI_ERROR (Status
)) {
1376 // Get data from SMM.
1378 *VariablePayloadSize
= SmmGetPayloadSize
->VariablePayloadSize
;
1381 if (CommBuffer
!= NULL
) {
1382 FreePool (CommBuffer
);
1384 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1389 This code gets information needed from SMM for runtime cache initialization.
1391 @param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes.
1392 @param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes.
1393 @param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes.
1394 @param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used.
1396 @retval EFI_SUCCESS Retrieved the size successfully.
1397 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
1398 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
1399 @retval Others Could not retrieve the size successfully.
1403 GetRuntimeCacheInfo (
1404 OUT UINTN
*TotalHobStorageSize
,
1405 OUT UINTN
*TotalNvStorageSize
,
1406 OUT UINTN
*TotalVolatileStorageSize
,
1407 OUT BOOLEAN
*AuthenticatedVariableUsage
1411 SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
*SmmGetRuntimeCacheInfo
;
1412 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1413 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1417 SmmGetRuntimeCacheInfo
= NULL
;
1418 CommBuffer
= mVariableBuffer
;
1420 if (TotalHobStorageSize
== NULL
|| TotalNvStorageSize
== NULL
|| TotalVolatileStorageSize
== NULL
|| AuthenticatedVariableUsage
== NULL
) {
1421 return EFI_INVALID_PARAMETER
;
1424 if (CommBuffer
== NULL
) {
1425 return EFI_OUT_OF_RESOURCES
;
1428 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1430 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
);
1431 ZeroMem (CommBuffer
, CommSize
);
1433 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) CommBuffer
;
1434 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1435 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
);
1437 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
1438 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO
;
1439 SmmGetRuntimeCacheInfo
= (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO
*) SmmVariableFunctionHeader
->Data
;
1442 // Send data to SMM.
1444 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, CommBuffer
, &CommSize
);
1445 ASSERT_EFI_ERROR (Status
);
1446 if (CommSize
<= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
1447 Status
= EFI_BAD_BUFFER_SIZE
;
1451 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1452 if (EFI_ERROR (Status
)) {
1457 // Get data from SMM.
1459 *TotalHobStorageSize
= SmmGetRuntimeCacheInfo
->TotalHobStorageSize
;
1460 *TotalNvStorageSize
= SmmGetRuntimeCacheInfo
->TotalNvStorageSize
;
1461 *TotalVolatileStorageSize
= SmmGetRuntimeCacheInfo
->TotalVolatileStorageSize
;
1462 *AuthenticatedVariableUsage
= SmmGetRuntimeCacheInfo
->AuthenticatedVariableUsage
;
1465 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1470 Sends the runtime variable cache context information to SMM.
1472 @retval EFI_SUCCESS Retrieved the size successfully.
1473 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.
1474 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.
1475 @retval Others Could not retrieve the size successfully.;
1479 SendRuntimeVariableCacheContextToSmm (
1484 SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
*SmmRuntimeVarCacheContext
;
1485 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
1486 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
1490 SmmRuntimeVarCacheContext
= NULL
;
1491 CommBuffer
= mVariableBuffer
;
1493 if (CommBuffer
== NULL
) {
1494 return EFI_OUT_OF_RESOURCES
;
1497 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
1500 // Init the communicate buffer. The buffer data size is:
1501 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);
1503 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
);
1504 ZeroMem (CommBuffer
, CommSize
);
1506 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) CommBuffer
;
1507 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
1508 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
);
1510 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
1511 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT
;
1512 SmmRuntimeVarCacheContext
= (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT
*) SmmVariableFunctionHeader
->Data
;
1514 SmmRuntimeVarCacheContext
->RuntimeHobCache
= mVariableRuntimeHobCacheBuffer
;
1515 SmmRuntimeVarCacheContext
->RuntimeVolatileCache
= mVariableRuntimeVolatileCacheBuffer
;
1516 SmmRuntimeVarCacheContext
->RuntimeNvCache
= mVariableRuntimeNvCacheBuffer
;
1517 SmmRuntimeVarCacheContext
->PendingUpdate
= &mVariableRuntimeCachePendingUpdate
;
1518 SmmRuntimeVarCacheContext
->ReadLock
= &mVariableRuntimeCacheReadLock
;
1519 SmmRuntimeVarCacheContext
->HobFlushComplete
= &mHobFlushComplete
;
1522 // Send data to SMM.
1524 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, CommBuffer
, &CommSize
);
1525 ASSERT_EFI_ERROR (Status
);
1526 if (CommSize
<= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
1527 Status
= EFI_BAD_BUFFER_SIZE
;
1531 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
1532 if (EFI_ERROR (Status
)) {
1537 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
1542 Initialize variable service and install Variable Architectural protocol.
1544 @param[in] Event Event whose notification function is being invoked.
1545 @param[in] Context Pointer to the notification function's context.
1557 Status
= gBS
->LocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**) &mSmmVariable
);
1558 if (EFI_ERROR (Status
)) {
1562 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &mSmmCommunication
);
1563 ASSERT_EFI_ERROR (Status
);
1566 // Allocate memory for variable communicate buffer.
1568 Status
= GetVariablePayloadSize (&mVariableBufferPayloadSize
);
1569 ASSERT_EFI_ERROR (Status
);
1570 mVariableBufferSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ mVariableBufferPayloadSize
;
1571 mVariableBuffer
= AllocateRuntimePool (mVariableBufferSize
);
1572 ASSERT (mVariableBuffer
!= NULL
);
1575 // Save the buffer physical address used for SMM conmunication.
1577 mVariableBufferPhysical
= mVariableBuffer
;
1579 if (FeaturePcdGet (PcdEnableVariableRuntimeCache
)) {
1580 DEBUG ((DEBUG_INFO
, "Variable driver runtime cache is enabled.\n"));
1582 // Allocate runtime variable cache memory buffers.
1584 Status
= GetRuntimeCacheInfo (
1585 &mVariableRuntimeHobCacheBufferSize
,
1586 &mVariableRuntimeNvCacheBufferSize
,
1587 &mVariableRuntimeVolatileCacheBufferSize
,
1588 &mVariableAuthFormat
1590 if (!EFI_ERROR (Status
)) {
1591 Status
= InitVariableCache (&mVariableRuntimeHobCacheBuffer
, &mVariableRuntimeHobCacheBufferSize
);
1592 if (!EFI_ERROR (Status
)) {
1593 Status
= InitVariableCache (&mVariableRuntimeNvCacheBuffer
, &mVariableRuntimeNvCacheBufferSize
);
1594 if (!EFI_ERROR (Status
)) {
1595 Status
= InitVariableCache (&mVariableRuntimeVolatileCacheBuffer
, &mVariableRuntimeVolatileCacheBufferSize
);
1596 if (!EFI_ERROR (Status
)) {
1597 Status
= SendRuntimeVariableCacheContextToSmm ();
1598 if (!EFI_ERROR (Status
)) {
1599 SyncRuntimeCache ();
1604 if (EFI_ERROR (Status
)) {
1605 mVariableRuntimeHobCacheBuffer
= NULL
;
1606 mVariableRuntimeNvCacheBuffer
= NULL
;
1607 mVariableRuntimeVolatileCacheBuffer
= NULL
;
1610 ASSERT_EFI_ERROR (Status
);
1612 DEBUG ((DEBUG_INFO
, "Variable driver runtime cache is disabled.\n"));
1615 gRT
->GetVariable
= RuntimeServiceGetVariable
;
1616 gRT
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
1617 gRT
->SetVariable
= RuntimeServiceSetVariable
;
1618 gRT
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
1621 // Install the Variable Architectural Protocol on a new handle.
1623 Status
= gBS
->InstallProtocolInterface (
1625 &gEfiVariableArchProtocolGuid
,
1626 EFI_NATIVE_INTERFACE
,
1629 ASSERT_EFI_ERROR (Status
);
1631 mVariableLock
.RequestToLock
= VariableLockRequestToLock
;
1632 Status
= gBS
->InstallMultipleProtocolInterfaces (
1634 &gEdkiiVariableLockProtocolGuid
,
1638 ASSERT_EFI_ERROR (Status
);
1640 mVarCheck
.RegisterSetVariableCheckHandler
= VarCheckRegisterSetVariableCheckHandler
;
1641 mVarCheck
.VariablePropertySet
= VarCheckVariablePropertySet
;
1642 mVarCheck
.VariablePropertyGet
= VarCheckVariablePropertyGet
;
1643 Status
= gBS
->InstallMultipleProtocolInterfaces (
1645 &gEdkiiVarCheckProtocolGuid
,
1649 ASSERT_EFI_ERROR (Status
);
1651 gBS
->CloseEvent (Event
);
1656 SMM Non-Volatile variable write service is ready notify event handler.
1658 @param[in] Event Event whose notification function is being invoked.
1659 @param[in] Context Pointer to the notification function's context.
1664 SmmVariableWriteReady (
1673 // Check whether the protocol is installed or not.
1675 Status
= gBS
->LocateProtocol (&gSmmVariableWriteGuid
, NULL
, (VOID
**) &ProtocolOps
);
1676 if (EFI_ERROR (Status
)) {
1681 // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
1682 // Secure Boot Policy Variable change. Record their initial value.
1684 RecordSecureBootPolicyVarData();
1686 Status
= gBS
->InstallProtocolInterface (
1688 &gEfiVariableWriteArchProtocolGuid
,
1689 EFI_NATIVE_INTERFACE
,
1692 ASSERT_EFI_ERROR (Status
);
1694 gBS
->CloseEvent (Event
);
1699 Variable Driver main entry point. The Variable driver places the 4 EFI
1700 runtime services in the EFI System Table and installs arch protocols
1701 for variable read and write services being available. It also registers
1702 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1704 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1705 @param[in] SystemTable A pointer to the EFI System Table.
1707 @retval EFI_SUCCESS Variable service successfully initialized.
1712 VariableSmmRuntimeInitialize (
1713 IN EFI_HANDLE ImageHandle
,
1714 IN EFI_SYSTEM_TABLE
*SystemTable
1717 VOID
*SmmVariableRegistration
;
1718 VOID
*SmmVariableWriteRegistration
;
1719 EFI_EVENT OnReadyToBootEvent
;
1720 EFI_EVENT ExitBootServiceEvent
;
1721 EFI_EVENT LegacyBootEvent
;
1723 EfiInitializeLock (&mVariableServicesLock
, TPL_NOTIFY
);
1726 // Smm variable service is ready
1728 EfiCreateProtocolNotifyEvent (
1729 &gEfiSmmVariableProtocolGuid
,
1733 &SmmVariableRegistration
1737 // Smm Non-Volatile variable write service is ready
1739 EfiCreateProtocolNotifyEvent (
1740 &gSmmVariableWriteGuid
,
1742 SmmVariableWriteReady
,
1744 &SmmVariableWriteRegistration
1748 // Register the event to reclaim variable for OS usage.
1750 EfiCreateEventReadyToBootEx (
1758 // Register the event to inform SMM variable that it is at runtime.
1760 gBS
->CreateEventEx (
1765 &gEfiEventExitBootServicesGuid
,
1766 &ExitBootServiceEvent
1770 // Register the event to inform SMM variable that it is at runtime for legacy boot.
1771 // Reuse OnExitBootServices() here.
1773 EfiCreateEventLegacyBootEx(
1781 // Register the event to convert the pointer for runtime.
1783 gBS
->CreateEventEx (
1786 VariableAddressChangeEvent
,
1788 &gEfiEventVirtualAddressChangeGuid
,
1789 &mVirtualAddressChangeEvent