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 - 2017, 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"
43 EFI_HANDLE mHandle
= NULL
;
44 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
= NULL
;
45 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
46 EFI_SMM_COMMUNICATION_PROTOCOL
*mSmmCommunication
= NULL
;
47 UINT8
*mVariableBuffer
= NULL
;
48 UINT8
*mVariableBufferPhysical
= NULL
;
49 UINTN mVariableBufferSize
;
50 UINTN mVariableBufferPayloadSize
;
51 EFI_LOCK mVariableServicesLock
;
52 EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock
;
53 EDKII_VAR_CHECK_PROTOCOL mVarCheck
;
56 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
57 Record their initial State when variable write service is ready.
62 RecordSecureBootPolicyVarData(
67 Acquires lock only at boot time. Simply returns at runtime.
69 This is a temperary function that will be removed when
70 EfiAcquireLock() in UefiLib can handle the call in UEFI
71 Runtimer driver in RT phase.
72 It calls EfiAcquireLock() at boot time, and simply returns
75 @param Lock A pointer to the lock to acquire.
79 AcquireLockOnlyAtBootTime (
83 if (!EfiAtRuntime ()) {
84 EfiAcquireLock (Lock
);
89 Releases lock only at boot time. Simply returns at runtime.
91 This is a temperary function which will be removed when
92 EfiReleaseLock() in UefiLib can handle the call in UEFI
93 Runtimer driver in RT phase.
94 It calls EfiReleaseLock() at boot time and simply returns
97 @param Lock A pointer to the lock to release.
101 ReleaseLockOnlyAtBootTime (
105 if (!EfiAtRuntime ()) {
106 EfiReleaseLock (Lock
);
111 Initialize the communicate buffer using DataSize and Function.
113 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
116 Caution: This function may receive untrusted input.
117 The data size external input, so this function will validate it carefully to avoid buffer overflow.
119 @param[out] DataPtr Points to the data in the communicate buffer.
120 @param[in] DataSize The data size to send to SMM.
121 @param[in] Function The function number to initialize the communicate header.
123 @retval EFI_INVALID_PARAMETER The data size is too big.
124 @retval EFI_SUCCESS Find the specified variable.
128 InitCommunicateBuffer (
129 OUT VOID
**DataPtr OPTIONAL
,
134 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
135 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
138 if (DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
> mVariableBufferSize
) {
139 return EFI_INVALID_PARAMETER
;
142 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
143 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
144 SmmCommunicateHeader
->MessageLength
= DataSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
146 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
147 SmmVariableFunctionHeader
->Function
= Function
;
148 if (DataPtr
!= NULL
) {
149 *DataPtr
= SmmVariableFunctionHeader
->Data
;
157 Send the data in communicate buffer to SMM.
159 @param[in] DataSize This size of the function header and the data.
161 @retval EFI_SUCCESS Success is returned from the functin in SMM.
162 @retval Others Failure is returned from the function in SMM.
166 SendCommunicateBuffer (
172 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
173 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
175 CommSize
= DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
176 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, mVariableBufferPhysical
, &CommSize
);
177 ASSERT_EFI_ERROR (Status
);
179 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
180 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
181 return SmmVariableFunctionHeader
->ReturnStatus
;
185 Mark a variable that will become read-only after leaving the DXE phase of execution.
187 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
188 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
189 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
191 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
192 as pending to be read-only.
193 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
194 Or VariableName is an empty string.
195 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
196 already been signaled.
197 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
201 VariableLockRequestToLock (
202 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
203 IN CHAR16
*VariableName
,
204 IN EFI_GUID
*VendorGuid
208 UINTN VariableNameSize
;
210 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
212 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
213 return EFI_INVALID_PARAMETER
;
216 VariableNameSize
= StrSize (VariableName
);
217 VariableToLock
= NULL
;
220 // If VariableName exceeds SMM payload limit. Return failure
222 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
)) {
223 return EFI_INVALID_PARAMETER
;
226 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
229 // Init the communicate buffer. The buffer data size is:
230 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
232 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
) + VariableNameSize
;
233 Status
= InitCommunicateBuffer ((VOID
**) &VariableToLock
, PayloadSize
, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
);
234 if (EFI_ERROR (Status
)) {
237 ASSERT (VariableToLock
!= NULL
);
239 CopyGuid (&VariableToLock
->Guid
, VendorGuid
);
240 VariableToLock
->NameSize
= VariableNameSize
;
241 CopyMem (VariableToLock
->Name
, VariableName
, VariableToLock
->NameSize
);
246 Status
= SendCommunicateBuffer (PayloadSize
);
249 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
254 Register SetVariable check handler.
256 @param[in] Handler Pointer to check handler.
258 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
259 @retval EFI_INVALID_PARAMETER Handler is NULL.
260 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
261 already been signaled.
262 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
263 @retval EFI_UNSUPPORTED This interface is not implemented.
264 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
269 VarCheckRegisterSetVariableCheckHandler (
270 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
273 return EFI_UNSUPPORTED
;
277 Variable property set.
279 @param[in] Name Pointer to the variable name.
280 @param[in] Guid Pointer to the vendor GUID.
281 @param[in] VariableProperty Pointer to the input variable property.
283 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
284 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
285 or the fields of VariableProperty are not valid.
286 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
287 already been signaled.
288 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
293 VarCheckVariablePropertySet (
296 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
300 UINTN VariableNameSize
;
302 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
304 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
305 return EFI_INVALID_PARAMETER
;
308 if (VariableProperty
== NULL
) {
309 return EFI_INVALID_PARAMETER
;
312 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
313 return EFI_INVALID_PARAMETER
;
316 VariableNameSize
= StrSize (Name
);
317 CommVariableProperty
= NULL
;
320 // If VariableName exceeds SMM payload limit. Return failure
322 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
323 return EFI_INVALID_PARAMETER
;
326 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
329 // Init the communicate buffer. The buffer data size is:
330 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
332 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
333 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
);
334 if (EFI_ERROR (Status
)) {
337 ASSERT (CommVariableProperty
!= NULL
);
339 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
340 CopyMem (&CommVariableProperty
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
341 CommVariableProperty
->NameSize
= VariableNameSize
;
342 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
347 Status
= SendCommunicateBuffer (PayloadSize
);
350 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
355 Variable property get.
357 @param[in] Name Pointer to the variable name.
358 @param[in] Guid Pointer to the vendor GUID.
359 @param[out] VariableProperty Pointer to the output variable property.
361 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
362 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
363 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
368 VarCheckVariablePropertyGet (
371 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
375 UINTN VariableNameSize
;
377 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
379 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
380 return EFI_INVALID_PARAMETER
;
383 if (VariableProperty
== NULL
) {
384 return EFI_INVALID_PARAMETER
;
387 VariableNameSize
= StrSize (Name
);
388 CommVariableProperty
= NULL
;
391 // If VariableName exceeds SMM payload limit. Return failure
393 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
394 return EFI_INVALID_PARAMETER
;
397 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
400 // Init the communicate buffer. The buffer data size is:
401 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
403 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
404 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
);
405 if (EFI_ERROR (Status
)) {
408 ASSERT (CommVariableProperty
!= NULL
);
410 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
411 CommVariableProperty
->NameSize
= VariableNameSize
;
412 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
417 Status
= SendCommunicateBuffer (PayloadSize
);
418 if (Status
== EFI_SUCCESS
) {
419 CopyMem (VariableProperty
, &CommVariableProperty
->VariableProperty
, sizeof (*VariableProperty
));
423 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
428 This code finds variable in storage blocks (Volatile or Non-Volatile).
430 Caution: This function may receive untrusted input.
431 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
433 @param[in] VariableName Name of Variable to be found.
434 @param[in] VendorGuid Variable vendor GUID.
435 @param[out] Attributes Attribute value of the variable found.
436 @param[in, out] DataSize Size of Data found. If size is less than the
437 data, this value contains the required size.
438 @param[out] Data Data pointer.
440 @retval EFI_INVALID_PARAMETER Invalid parameter.
441 @retval EFI_SUCCESS Find the specified variable.
442 @retval EFI_NOT_FOUND Not found.
443 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
448 RuntimeServiceGetVariable (
449 IN CHAR16
*VariableName
,
450 IN EFI_GUID
*VendorGuid
,
451 OUT UINT32
*Attributes OPTIONAL
,
452 IN OUT UINTN
*DataSize
,
458 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
460 UINTN VariableNameSize
;
462 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
463 return EFI_INVALID_PARAMETER
;
466 TempDataSize
= *DataSize
;
467 VariableNameSize
= StrSize (VariableName
);
468 SmmVariableHeader
= NULL
;
471 // If VariableName exceeds SMM payload limit. Return failure
473 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
474 return EFI_INVALID_PARAMETER
;
477 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
480 // Init the communicate buffer. The buffer data size is:
481 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
483 if (TempDataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
) {
485 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
487 TempDataSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
;
489 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ TempDataSize
;
491 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_VARIABLE
);
492 if (EFI_ERROR (Status
)) {
495 ASSERT (SmmVariableHeader
!= NULL
);
497 CopyGuid (&SmmVariableHeader
->Guid
, VendorGuid
);
498 SmmVariableHeader
->DataSize
= TempDataSize
;
499 SmmVariableHeader
->NameSize
= VariableNameSize
;
500 if (Attributes
== NULL
) {
501 SmmVariableHeader
->Attributes
= 0;
503 SmmVariableHeader
->Attributes
= *Attributes
;
505 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
510 Status
= SendCommunicateBuffer (PayloadSize
);
513 // Get data from SMM.
515 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
517 // SMM CommBuffer DataSize can be a trimed value
518 // Only update DataSize when needed
520 *DataSize
= SmmVariableHeader
->DataSize
;
522 if (Attributes
!= NULL
) {
523 *Attributes
= SmmVariableHeader
->Attributes
;
526 if (EFI_ERROR (Status
)) {
531 CopyMem (Data
, (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, SmmVariableHeader
->DataSize
);
533 Status
= EFI_INVALID_PARAMETER
;
537 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
543 This code Finds the Next available variable.
545 @param[in, out] VariableNameSize Size of the variable name.
546 @param[in, out] VariableName Pointer to variable name.
547 @param[in, out] VendorGuid Variable Vendor Guid.
549 @retval EFI_INVALID_PARAMETER Invalid parameter.
550 @retval EFI_SUCCESS Find the specified variable.
551 @retval EFI_NOT_FOUND Not found.
552 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
557 RuntimeServiceGetNextVariableName (
558 IN OUT UINTN
*VariableNameSize
,
559 IN OUT CHAR16
*VariableName
,
560 IN OUT EFI_GUID
*VendorGuid
565 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*SmmGetNextVariableName
;
566 UINTN OutVariableNameSize
;
567 UINTN InVariableNameSize
;
569 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
570 return EFI_INVALID_PARAMETER
;
573 OutVariableNameSize
= *VariableNameSize
;
574 InVariableNameSize
= StrSize (VariableName
);
575 SmmGetNextVariableName
= NULL
;
578 // If input string exceeds SMM payload limit. Return failure
580 if (InVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
581 return EFI_INVALID_PARAMETER
;
584 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
587 // Init the communicate buffer. The buffer data size is:
588 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
590 if (OutVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
592 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
594 OutVariableNameSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
597 // Payload should be Guid + NameSize + MAX of Input & Output buffer
599 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + MAX (OutVariableNameSize
, InVariableNameSize
);
601 Status
= InitCommunicateBuffer ((VOID
**)&SmmGetNextVariableName
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
);
602 if (EFI_ERROR (Status
)) {
605 ASSERT (SmmGetNextVariableName
!= NULL
);
608 // SMM comm buffer->NameSize is buffer size for return string
610 SmmGetNextVariableName
->NameSize
= OutVariableNameSize
;
612 CopyGuid (&SmmGetNextVariableName
->Guid
, VendorGuid
);
616 CopyMem (SmmGetNextVariableName
->Name
, VariableName
, InVariableNameSize
);
617 if (OutVariableNameSize
> InVariableNameSize
) {
618 ZeroMem ((UINT8
*) SmmGetNextVariableName
->Name
+ InVariableNameSize
, OutVariableNameSize
- InVariableNameSize
);
624 Status
= SendCommunicateBuffer (PayloadSize
);
627 // Get data from SMM.
629 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
631 // SMM CommBuffer NameSize can be a trimed value
632 // Only update VariableNameSize when needed
634 *VariableNameSize
= SmmGetNextVariableName
->NameSize
;
636 if (EFI_ERROR (Status
)) {
640 CopyGuid (VendorGuid
, &SmmGetNextVariableName
->Guid
);
641 CopyMem (VariableName
, SmmGetNextVariableName
->Name
, SmmGetNextVariableName
->NameSize
);
644 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
649 This code sets variable in storage blocks (Volatile or Non-Volatile).
651 Caution: This function may receive untrusted input.
652 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
654 @param[in] VariableName Name of Variable to be found.
655 @param[in] VendorGuid Variable vendor GUID.
656 @param[in] Attributes Attribute value of the variable found
657 @param[in] DataSize Size of Data found. If size is less than the
658 data, this value contains the required size.
659 @param[in] Data Data pointer.
661 @retval EFI_INVALID_PARAMETER Invalid parameter.
662 @retval EFI_SUCCESS Set successfully.
663 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
664 @retval EFI_NOT_FOUND Not found.
665 @retval EFI_WRITE_PROTECTED Variable is read-only.
670 RuntimeServiceSetVariable (
671 IN CHAR16
*VariableName
,
672 IN EFI_GUID
*VendorGuid
,
673 IN UINT32 Attributes
,
680 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
681 UINTN VariableNameSize
;
684 // Check input parameters.
686 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
687 return EFI_INVALID_PARAMETER
;
690 if (DataSize
!= 0 && Data
== NULL
) {
691 return EFI_INVALID_PARAMETER
;
694 VariableNameSize
= StrSize (VariableName
);
695 SmmVariableHeader
= NULL
;
698 // If VariableName or DataSize exceeds SMM payload limit. Return failure
700 if ((VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
701 (DataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
)){
702 return EFI_INVALID_PARAMETER
;
705 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
708 // Init the communicate buffer. The buffer data size is:
709 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
711 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ DataSize
;
712 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_SET_VARIABLE
);
713 if (EFI_ERROR (Status
)) {
716 ASSERT (SmmVariableHeader
!= NULL
);
718 CopyGuid ((EFI_GUID
*) &SmmVariableHeader
->Guid
, VendorGuid
);
719 SmmVariableHeader
->DataSize
= DataSize
;
720 SmmVariableHeader
->NameSize
= VariableNameSize
;
721 SmmVariableHeader
->Attributes
= Attributes
;
722 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
723 CopyMem ((UINT8
*) SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, Data
, DataSize
);
728 Status
= SendCommunicateBuffer (PayloadSize
);
731 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
733 if (!EfiAtRuntime ()) {
734 if (!EFI_ERROR (Status
)) {
746 This code returns information about the EFI variables.
748 @param[in] Attributes Attributes bitmask to specify the type of variables
749 on which to return information.
750 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
751 for the EFI variables associated with the attributes specified.
752 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
753 for EFI variables associated with the attributes specified.
754 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
755 associated with the attributes specified.
757 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
758 @retval EFI_SUCCESS Query successfully.
759 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
764 RuntimeServiceQueryVariableInfo (
765 IN UINT32 Attributes
,
766 OUT UINT64
*MaximumVariableStorageSize
,
767 OUT UINT64
*RemainingVariableStorageSize
,
768 OUT UINT64
*MaximumVariableSize
773 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*SmmQueryVariableInfo
;
775 SmmQueryVariableInfo
= NULL
;
777 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
778 return EFI_INVALID_PARAMETER
;
781 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
784 // Init the communicate buffer. The buffer data size is:
785 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
787 PayloadSize
= sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
788 Status
= InitCommunicateBuffer ((VOID
**)&SmmQueryVariableInfo
, PayloadSize
, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
);
789 if (EFI_ERROR (Status
)) {
792 ASSERT (SmmQueryVariableInfo
!= NULL
);
794 SmmQueryVariableInfo
->Attributes
= Attributes
;
799 Status
= SendCommunicateBuffer (PayloadSize
);
800 if (EFI_ERROR (Status
)) {
805 // Get data from SMM.
807 *MaximumVariableSize
= SmmQueryVariableInfo
->MaximumVariableSize
;
808 *MaximumVariableStorageSize
= SmmQueryVariableInfo
->MaximumVariableStorageSize
;
809 *RemainingVariableStorageSize
= SmmQueryVariableInfo
->RemainingVariableStorageSize
;
812 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
818 Exit Boot Services Event notification handler.
820 Notify SMM variable driver about the event.
822 @param[in] Event Event whose notification function is being invoked.
823 @param[in] Context Pointer to the notification function's context.
834 // Init the communicate buffer. The buffer data size is:
835 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
837 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
);
842 SendCommunicateBuffer (0);
847 On Ready To Boot Services Event notification handler.
849 Notify SMM variable driver about the event.
851 @param[in] Event Event whose notification function is being invoked
852 @param[in] Context Pointer to the notification function's context
863 // Init the communicate buffer. The buffer data size is:
864 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
866 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT
);
871 SendCommunicateBuffer (0);
873 gBS
->CloseEvent (Event
);
878 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
880 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
881 It convers pointer to new virtual address.
883 @param[in] Event Event whose notification function is being invoked.
884 @param[in] Context Pointer to the notification function's context.
889 VariableAddressChangeEvent (
894 EfiConvertPointer (0x0, (VOID
**) &mVariableBuffer
);
895 EfiConvertPointer (0x0, (VOID
**) &mSmmCommunication
);
899 This code gets variable payload size.
901 @param[out] VariablePayloadSize Output pointer to variable payload size.
903 @retval EFI_SUCCESS Get successfully.
904 @retval Others Get unsuccessfully.
909 GetVariablePayloadSize (
910 OUT UINTN
*VariablePayloadSize
914 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*SmmGetPayloadSize
;
915 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
916 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
920 SmmGetPayloadSize
= NULL
;
923 if(VariablePayloadSize
== NULL
) {
924 return EFI_INVALID_PARAMETER
;
927 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
930 // Init the communicate buffer. The buffer data size is:
931 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
933 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
934 CommBuffer
= AllocateZeroPool (CommSize
);
935 if (CommBuffer
== NULL
) {
936 Status
= EFI_OUT_OF_RESOURCES
;
940 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) CommBuffer
;
941 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
942 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
944 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
945 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE
;
946 SmmGetPayloadSize
= (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*) SmmVariableFunctionHeader
->Data
;
951 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, CommBuffer
, &CommSize
);
952 ASSERT_EFI_ERROR (Status
);
954 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
955 if (EFI_ERROR (Status
)) {
960 // Get data from SMM.
962 *VariablePayloadSize
= SmmGetPayloadSize
->VariablePayloadSize
;
965 if (CommBuffer
!= NULL
) {
966 FreePool (CommBuffer
);
968 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
973 Initialize variable service and install Variable Architectural protocol.
975 @param[in] Event Event whose notification function is being invoked.
976 @param[in] Context Pointer to the notification function's context.
988 Status
= gBS
->LocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
989 if (EFI_ERROR (Status
)) {
993 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &mSmmCommunication
);
994 ASSERT_EFI_ERROR (Status
);
997 // Allocate memory for variable communicate buffer.
999 Status
= GetVariablePayloadSize (&mVariableBufferPayloadSize
);
1000 ASSERT_EFI_ERROR (Status
);
1001 mVariableBufferSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ mVariableBufferPayloadSize
;
1002 mVariableBuffer
= AllocateRuntimePool (mVariableBufferSize
);
1003 ASSERT (mVariableBuffer
!= NULL
);
1006 // Save the buffer physical address used for SMM conmunication.
1008 mVariableBufferPhysical
= mVariableBuffer
;
1010 gRT
->GetVariable
= RuntimeServiceGetVariable
;
1011 gRT
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
1012 gRT
->SetVariable
= RuntimeServiceSetVariable
;
1013 gRT
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
1016 // Install the Variable Architectural Protocol on a new handle.
1018 Status
= gBS
->InstallProtocolInterface (
1020 &gEfiVariableArchProtocolGuid
,
1021 EFI_NATIVE_INTERFACE
,
1024 ASSERT_EFI_ERROR (Status
);
1026 mVariableLock
.RequestToLock
= VariableLockRequestToLock
;
1027 Status
= gBS
->InstallMultipleProtocolInterfaces (
1029 &gEdkiiVariableLockProtocolGuid
,
1033 ASSERT_EFI_ERROR (Status
);
1035 mVarCheck
.RegisterSetVariableCheckHandler
= VarCheckRegisterSetVariableCheckHandler
;
1036 mVarCheck
.VariablePropertySet
= VarCheckVariablePropertySet
;
1037 mVarCheck
.VariablePropertyGet
= VarCheckVariablePropertyGet
;
1038 Status
= gBS
->InstallMultipleProtocolInterfaces (
1040 &gEdkiiVarCheckProtocolGuid
,
1044 ASSERT_EFI_ERROR (Status
);
1046 gBS
->CloseEvent (Event
);
1051 SMM Non-Volatile variable write service is ready notify event handler.
1053 @param[in] Event Event whose notification function is being invoked.
1054 @param[in] Context Pointer to the notification function's context.
1059 SmmVariableWriteReady (
1068 // Check whether the protocol is installed or not.
1070 Status
= gBS
->LocateProtocol (&gSmmVariableWriteGuid
, NULL
, (VOID
**) &ProtocolOps
);
1071 if (EFI_ERROR (Status
)) {
1076 // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
1077 // Secure Boot Policy Variable change. Record their initial value.
1079 RecordSecureBootPolicyVarData();
1081 Status
= gBS
->InstallProtocolInterface (
1083 &gEfiVariableWriteArchProtocolGuid
,
1084 EFI_NATIVE_INTERFACE
,
1087 ASSERT_EFI_ERROR (Status
);
1089 gBS
->CloseEvent (Event
);
1094 Variable Driver main entry point. The Variable driver places the 4 EFI
1095 runtime services in the EFI System Table and installs arch protocols
1096 for variable read and write services being available. It also registers
1097 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1099 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1100 @param[in] SystemTable A pointer to the EFI System Table.
1102 @retval EFI_SUCCESS Variable service successfully initialized.
1107 VariableSmmRuntimeInitialize (
1108 IN EFI_HANDLE ImageHandle
,
1109 IN EFI_SYSTEM_TABLE
*SystemTable
1112 VOID
*SmmVariableRegistration
;
1113 VOID
*SmmVariableWriteRegistration
;
1114 EFI_EVENT OnReadyToBootEvent
;
1115 EFI_EVENT ExitBootServiceEvent
;
1116 EFI_EVENT LegacyBootEvent
;
1118 EfiInitializeLock (&mVariableServicesLock
, TPL_NOTIFY
);
1121 // Smm variable service is ready
1123 EfiCreateProtocolNotifyEvent (
1124 &gEfiSmmVariableProtocolGuid
,
1128 &SmmVariableRegistration
1132 // Smm Non-Volatile variable write service is ready
1134 EfiCreateProtocolNotifyEvent (
1135 &gSmmVariableWriteGuid
,
1137 SmmVariableWriteReady
,
1139 &SmmVariableWriteRegistration
1143 // Register the event to reclaim variable for OS usage.
1145 EfiCreateEventReadyToBootEx (
1153 // Register the event to inform SMM variable that it is at runtime.
1155 gBS
->CreateEventEx (
1160 &gEfiEventExitBootServicesGuid
,
1161 &ExitBootServiceEvent
1165 // Register the event to inform SMM variable that it is at runtime for legacy boot.
1166 // Reuse OnExitBootServices() here.
1168 EfiCreateEventLegacyBootEx(
1176 // Register the event to convert the pointer for runtime.
1178 gBS
->CreateEventEx (
1181 VariableAddressChangeEvent
,
1183 &gEfiEventVirtualAddressChangeGuid
,
1184 &mVirtualAddressChangeEvent