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 This program and the accompanying materials
18 are licensed and made available under the terms and conditions of the BSD License
19 which accompanies this distribution. The full text of the license may be found at
20 http://opensource.org/licenses/bsd-license.php
22 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
23 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
27 #include <Protocol/VariableWrite.h>
28 #include <Protocol/Variable.h>
29 #include <Protocol/SmmCommunication.h>
30 #include <Protocol/SmmVariable.h>
31 #include <Protocol/VariableLock.h>
32 #include <Protocol/VarCheck.h>
34 #include <Library/UefiBootServicesTableLib.h>
35 #include <Library/UefiRuntimeServicesTableLib.h>
36 #include <Library/MemoryAllocationLib.h>
37 #include <Library/UefiDriverEntryPoint.h>
38 #include <Library/UefiRuntimeLib.h>
39 #include <Library/BaseMemoryLib.h>
40 #include <Library/DebugLib.h>
41 #include <Library/UefiLib.h>
42 #include <Library/BaseLib.h>
44 #include <Guid/EventGroup.h>
45 #include <Guid/SmmVariableCommon.h>
47 #include "PrivilegePolymorphic.h"
49 EFI_HANDLE mHandle
= NULL
;
50 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
= NULL
;
51 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
52 EFI_SMM_COMMUNICATION_PROTOCOL
*mSmmCommunication
= NULL
;
53 UINT8
*mVariableBuffer
= NULL
;
54 UINT8
*mVariableBufferPhysical
= NULL
;
55 UINTN mVariableBufferSize
;
56 UINTN mVariableBufferPayloadSize
;
57 EFI_LOCK mVariableServicesLock
;
58 EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock
;
59 EDKII_VAR_CHECK_PROTOCOL mVarCheck
;
62 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
63 Record their initial State when variable write service is ready.
68 RecordSecureBootPolicyVarData(
73 Acquires lock only at boot time. Simply returns at runtime.
75 This is a temperary function that will be removed when
76 EfiAcquireLock() in UefiLib can handle the call in UEFI
77 Runtimer driver in RT phase.
78 It calls EfiAcquireLock() at boot time, and simply returns
81 @param Lock A pointer to the lock to acquire.
85 AcquireLockOnlyAtBootTime (
89 if (!EfiAtRuntime ()) {
90 EfiAcquireLock (Lock
);
95 Releases lock only at boot time. Simply returns at runtime.
97 This is a temperary function which will be removed when
98 EfiReleaseLock() in UefiLib can handle the call in UEFI
99 Runtimer driver in RT phase.
100 It calls EfiReleaseLock() at boot time and simply returns
103 @param Lock A pointer to the lock to release.
107 ReleaseLockOnlyAtBootTime (
111 if (!EfiAtRuntime ()) {
112 EfiReleaseLock (Lock
);
117 Initialize the communicate buffer using DataSize and Function.
119 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
122 Caution: This function may receive untrusted input.
123 The data size external input, so this function will validate it carefully to avoid buffer overflow.
125 @param[out] DataPtr Points to the data in the communicate buffer.
126 @param[in] DataSize The data size to send to SMM.
127 @param[in] Function The function number to initialize the communicate header.
129 @retval EFI_INVALID_PARAMETER The data size is too big.
130 @retval EFI_SUCCESS Find the specified variable.
134 InitCommunicateBuffer (
135 OUT VOID
**DataPtr OPTIONAL
,
140 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
141 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
144 if (DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
> mVariableBufferSize
) {
145 return EFI_INVALID_PARAMETER
;
148 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
149 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
150 SmmCommunicateHeader
->MessageLength
= DataSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
152 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
153 SmmVariableFunctionHeader
->Function
= Function
;
154 if (DataPtr
!= NULL
) {
155 *DataPtr
= SmmVariableFunctionHeader
->Data
;
163 Send the data in communicate buffer to SMM.
165 @param[in] DataSize This size of the function header and the data.
167 @retval EFI_SUCCESS Success is returned from the functin in SMM.
168 @retval Others Failure is returned from the function in SMM.
172 SendCommunicateBuffer (
178 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
179 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
181 CommSize
= DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
182 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, mVariableBufferPhysical
, &CommSize
);
183 ASSERT_EFI_ERROR (Status
);
185 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
186 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
187 return SmmVariableFunctionHeader
->ReturnStatus
;
191 Mark a variable that will become read-only after leaving the DXE phase of execution.
193 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
194 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
195 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
197 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
198 as pending to be read-only.
199 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
200 Or VariableName is an empty string.
201 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
202 already been signaled.
203 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
207 VariableLockRequestToLock (
208 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
209 IN CHAR16
*VariableName
,
210 IN EFI_GUID
*VendorGuid
214 UINTN VariableNameSize
;
216 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
218 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
219 return EFI_INVALID_PARAMETER
;
222 VariableNameSize
= StrSize (VariableName
);
223 VariableToLock
= NULL
;
226 // If VariableName exceeds SMM payload limit. Return failure
228 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
)) {
229 return EFI_INVALID_PARAMETER
;
232 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
235 // Init the communicate buffer. The buffer data size is:
236 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
238 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
) + VariableNameSize
;
239 Status
= InitCommunicateBuffer ((VOID
**) &VariableToLock
, PayloadSize
, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
);
240 if (EFI_ERROR (Status
)) {
243 ASSERT (VariableToLock
!= NULL
);
245 CopyGuid (&VariableToLock
->Guid
, VendorGuid
);
246 VariableToLock
->NameSize
= VariableNameSize
;
247 CopyMem (VariableToLock
->Name
, VariableName
, VariableToLock
->NameSize
);
252 Status
= SendCommunicateBuffer (PayloadSize
);
255 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
260 Register SetVariable check handler.
262 @param[in] Handler Pointer to check handler.
264 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
265 @retval EFI_INVALID_PARAMETER Handler is NULL.
266 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
267 already been signaled.
268 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
269 @retval EFI_UNSUPPORTED This interface is not implemented.
270 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
275 VarCheckRegisterSetVariableCheckHandler (
276 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
279 return EFI_UNSUPPORTED
;
283 Variable property set.
285 @param[in] Name Pointer to the variable name.
286 @param[in] Guid Pointer to the vendor GUID.
287 @param[in] VariableProperty Pointer to the input variable property.
289 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
290 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
291 or the fields of VariableProperty are not valid.
292 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
293 already been signaled.
294 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
299 VarCheckVariablePropertySet (
302 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
306 UINTN VariableNameSize
;
308 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
310 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
311 return EFI_INVALID_PARAMETER
;
314 if (VariableProperty
== NULL
) {
315 return EFI_INVALID_PARAMETER
;
318 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
319 return EFI_INVALID_PARAMETER
;
322 VariableNameSize
= StrSize (Name
);
323 CommVariableProperty
= NULL
;
326 // If VariableName exceeds SMM payload limit. Return failure
328 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
329 return EFI_INVALID_PARAMETER
;
332 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
335 // Init the communicate buffer. The buffer data size is:
336 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
338 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
339 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
);
340 if (EFI_ERROR (Status
)) {
343 ASSERT (CommVariableProperty
!= NULL
);
345 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
346 CopyMem (&CommVariableProperty
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
347 CommVariableProperty
->NameSize
= VariableNameSize
;
348 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
353 Status
= SendCommunicateBuffer (PayloadSize
);
356 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
361 Variable property get.
363 @param[in] Name Pointer to the variable name.
364 @param[in] Guid Pointer to the vendor GUID.
365 @param[out] VariableProperty Pointer to the output variable property.
367 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
368 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
369 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
374 VarCheckVariablePropertyGet (
377 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
381 UINTN VariableNameSize
;
383 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
385 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
386 return EFI_INVALID_PARAMETER
;
389 if (VariableProperty
== NULL
) {
390 return EFI_INVALID_PARAMETER
;
393 VariableNameSize
= StrSize (Name
);
394 CommVariableProperty
= NULL
;
397 // If VariableName exceeds SMM payload limit. Return failure
399 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
400 return EFI_INVALID_PARAMETER
;
403 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
406 // Init the communicate buffer. The buffer data size is:
407 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
409 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
410 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
);
411 if (EFI_ERROR (Status
)) {
414 ASSERT (CommVariableProperty
!= NULL
);
416 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
417 CommVariableProperty
->NameSize
= VariableNameSize
;
418 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
423 Status
= SendCommunicateBuffer (PayloadSize
);
424 if (Status
== EFI_SUCCESS
) {
425 CopyMem (VariableProperty
, &CommVariableProperty
->VariableProperty
, sizeof (*VariableProperty
));
429 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
434 This code finds variable in storage blocks (Volatile or Non-Volatile).
436 Caution: This function may receive untrusted input.
437 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
439 @param[in] VariableName Name of Variable to be found.
440 @param[in] VendorGuid Variable vendor GUID.
441 @param[out] Attributes Attribute value of the variable found.
442 @param[in, out] DataSize Size of Data found. If size is less than the
443 data, this value contains the required size.
444 @param[out] Data Data pointer.
446 @retval EFI_INVALID_PARAMETER Invalid parameter.
447 @retval EFI_SUCCESS Find the specified variable.
448 @retval EFI_NOT_FOUND Not found.
449 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
454 RuntimeServiceGetVariable (
455 IN CHAR16
*VariableName
,
456 IN EFI_GUID
*VendorGuid
,
457 OUT UINT32
*Attributes OPTIONAL
,
458 IN OUT UINTN
*DataSize
,
464 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
466 UINTN VariableNameSize
;
468 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
469 return EFI_INVALID_PARAMETER
;
472 TempDataSize
= *DataSize
;
473 VariableNameSize
= StrSize (VariableName
);
474 SmmVariableHeader
= NULL
;
477 // If VariableName exceeds SMM payload limit. Return failure
479 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
480 return EFI_INVALID_PARAMETER
;
483 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
486 // Init the communicate buffer. The buffer data size is:
487 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
489 if (TempDataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
) {
491 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
493 TempDataSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
;
495 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ TempDataSize
;
497 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_VARIABLE
);
498 if (EFI_ERROR (Status
)) {
501 ASSERT (SmmVariableHeader
!= NULL
);
503 CopyGuid (&SmmVariableHeader
->Guid
, VendorGuid
);
504 SmmVariableHeader
->DataSize
= TempDataSize
;
505 SmmVariableHeader
->NameSize
= VariableNameSize
;
506 if (Attributes
== NULL
) {
507 SmmVariableHeader
->Attributes
= 0;
509 SmmVariableHeader
->Attributes
= *Attributes
;
511 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
516 Status
= SendCommunicateBuffer (PayloadSize
);
519 // Get data from SMM.
521 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
523 // SMM CommBuffer DataSize can be a trimed value
524 // Only update DataSize when needed
526 *DataSize
= SmmVariableHeader
->DataSize
;
528 if (Attributes
!= NULL
) {
529 *Attributes
= SmmVariableHeader
->Attributes
;
532 if (EFI_ERROR (Status
)) {
537 CopyMem (Data
, (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, SmmVariableHeader
->DataSize
);
539 Status
= EFI_INVALID_PARAMETER
;
543 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
549 This code Finds the Next available variable.
551 @param[in, out] VariableNameSize Size of the variable name.
552 @param[in, out] VariableName Pointer to variable name.
553 @param[in, out] VendorGuid Variable Vendor Guid.
555 @retval EFI_INVALID_PARAMETER Invalid parameter.
556 @retval EFI_SUCCESS Find the specified variable.
557 @retval EFI_NOT_FOUND Not found.
558 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
563 RuntimeServiceGetNextVariableName (
564 IN OUT UINTN
*VariableNameSize
,
565 IN OUT CHAR16
*VariableName
,
566 IN OUT EFI_GUID
*VendorGuid
571 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*SmmGetNextVariableName
;
572 UINTN OutVariableNameSize
;
573 UINTN InVariableNameSize
;
575 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
576 return EFI_INVALID_PARAMETER
;
579 OutVariableNameSize
= *VariableNameSize
;
580 InVariableNameSize
= StrSize (VariableName
);
581 SmmGetNextVariableName
= NULL
;
584 // If input string exceeds SMM payload limit. Return failure
586 if (InVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
587 return EFI_INVALID_PARAMETER
;
590 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
593 // Init the communicate buffer. The buffer data size is:
594 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
596 if (OutVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
598 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
600 OutVariableNameSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
603 // Payload should be Guid + NameSize + MAX of Input & Output buffer
605 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + MAX (OutVariableNameSize
, InVariableNameSize
);
607 Status
= InitCommunicateBuffer ((VOID
**)&SmmGetNextVariableName
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
);
608 if (EFI_ERROR (Status
)) {
611 ASSERT (SmmGetNextVariableName
!= NULL
);
614 // SMM comm buffer->NameSize is buffer size for return string
616 SmmGetNextVariableName
->NameSize
= OutVariableNameSize
;
618 CopyGuid (&SmmGetNextVariableName
->Guid
, VendorGuid
);
622 CopyMem (SmmGetNextVariableName
->Name
, VariableName
, InVariableNameSize
);
623 if (OutVariableNameSize
> InVariableNameSize
) {
624 ZeroMem ((UINT8
*) SmmGetNextVariableName
->Name
+ InVariableNameSize
, OutVariableNameSize
- InVariableNameSize
);
630 Status
= SendCommunicateBuffer (PayloadSize
);
633 // Get data from SMM.
635 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
637 // SMM CommBuffer NameSize can be a trimed value
638 // Only update VariableNameSize when needed
640 *VariableNameSize
= SmmGetNextVariableName
->NameSize
;
642 if (EFI_ERROR (Status
)) {
646 CopyGuid (VendorGuid
, &SmmGetNextVariableName
->Guid
);
647 CopyMem (VariableName
, SmmGetNextVariableName
->Name
, SmmGetNextVariableName
->NameSize
);
650 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
655 This code sets variable in storage blocks (Volatile or Non-Volatile).
657 Caution: This function may receive untrusted input.
658 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
660 @param[in] VariableName Name of Variable to be found.
661 @param[in] VendorGuid Variable vendor GUID.
662 @param[in] Attributes Attribute value of the variable found
663 @param[in] DataSize Size of Data found. If size is less than the
664 data, this value contains the required size.
665 @param[in] Data Data pointer.
667 @retval EFI_INVALID_PARAMETER Invalid parameter.
668 @retval EFI_SUCCESS Set successfully.
669 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
670 @retval EFI_NOT_FOUND Not found.
671 @retval EFI_WRITE_PROTECTED Variable is read-only.
676 RuntimeServiceSetVariable (
677 IN CHAR16
*VariableName
,
678 IN EFI_GUID
*VendorGuid
,
679 IN UINT32 Attributes
,
686 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
687 UINTN VariableNameSize
;
690 // Check input parameters.
692 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
693 return EFI_INVALID_PARAMETER
;
696 if (DataSize
!= 0 && Data
== NULL
) {
697 return EFI_INVALID_PARAMETER
;
700 VariableNameSize
= StrSize (VariableName
);
701 SmmVariableHeader
= NULL
;
704 // If VariableName or DataSize exceeds SMM payload limit. Return failure
706 if ((VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
707 (DataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
)){
708 return EFI_INVALID_PARAMETER
;
711 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
714 // Init the communicate buffer. The buffer data size is:
715 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
717 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ DataSize
;
718 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_SET_VARIABLE
);
719 if (EFI_ERROR (Status
)) {
722 ASSERT (SmmVariableHeader
!= NULL
);
724 CopyGuid ((EFI_GUID
*) &SmmVariableHeader
->Guid
, VendorGuid
);
725 SmmVariableHeader
->DataSize
= DataSize
;
726 SmmVariableHeader
->NameSize
= VariableNameSize
;
727 SmmVariableHeader
->Attributes
= Attributes
;
728 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
729 CopyMem ((UINT8
*) SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, Data
, DataSize
);
734 Status
= SendCommunicateBuffer (PayloadSize
);
737 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
739 if (!EfiAtRuntime ()) {
740 if (!EFI_ERROR (Status
)) {
752 This code returns information about the EFI variables.
754 @param[in] Attributes Attributes bitmask to specify the type of variables
755 on which to return information.
756 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
757 for the EFI variables associated with the attributes specified.
758 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
759 for EFI variables associated with the attributes specified.
760 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
761 associated with the attributes specified.
763 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
764 @retval EFI_SUCCESS Query successfully.
765 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
770 RuntimeServiceQueryVariableInfo (
771 IN UINT32 Attributes
,
772 OUT UINT64
*MaximumVariableStorageSize
,
773 OUT UINT64
*RemainingVariableStorageSize
,
774 OUT UINT64
*MaximumVariableSize
779 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*SmmQueryVariableInfo
;
781 SmmQueryVariableInfo
= NULL
;
783 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
784 return EFI_INVALID_PARAMETER
;
787 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
790 // Init the communicate buffer. The buffer data size is:
791 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
793 PayloadSize
= sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
794 Status
= InitCommunicateBuffer ((VOID
**)&SmmQueryVariableInfo
, PayloadSize
, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
);
795 if (EFI_ERROR (Status
)) {
798 ASSERT (SmmQueryVariableInfo
!= NULL
);
800 SmmQueryVariableInfo
->Attributes
= Attributes
;
805 Status
= SendCommunicateBuffer (PayloadSize
);
806 if (EFI_ERROR (Status
)) {
811 // Get data from SMM.
813 *MaximumVariableSize
= SmmQueryVariableInfo
->MaximumVariableSize
;
814 *MaximumVariableStorageSize
= SmmQueryVariableInfo
->MaximumVariableStorageSize
;
815 *RemainingVariableStorageSize
= SmmQueryVariableInfo
->RemainingVariableStorageSize
;
818 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
824 Exit Boot Services Event notification handler.
826 Notify SMM variable driver about the event.
828 @param[in] Event Event whose notification function is being invoked.
829 @param[in] Context Pointer to the notification function's context.
840 // Init the communicate buffer. The buffer data size is:
841 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
843 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
);
848 SendCommunicateBuffer (0);
853 On Ready To Boot Services Event notification handler.
855 Notify SMM variable driver about the event.
857 @param[in] Event Event whose notification function is being invoked
858 @param[in] Context Pointer to the notification function's context
869 // Init the communicate buffer. The buffer data size is:
870 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
872 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT
);
877 SendCommunicateBuffer (0);
879 gBS
->CloseEvent (Event
);
884 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
886 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
887 It convers pointer to new virtual address.
889 @param[in] Event Event whose notification function is being invoked.
890 @param[in] Context Pointer to the notification function's context.
895 VariableAddressChangeEvent (
900 EfiConvertPointer (0x0, (VOID
**) &mVariableBuffer
);
901 EfiConvertPointer (0x0, (VOID
**) &mSmmCommunication
);
905 This code gets variable payload size.
907 @param[out] VariablePayloadSize Output pointer to variable payload size.
909 @retval EFI_SUCCESS Get successfully.
910 @retval Others Get unsuccessfully.
915 GetVariablePayloadSize (
916 OUT UINTN
*VariablePayloadSize
920 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*SmmGetPayloadSize
;
921 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
922 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
926 SmmGetPayloadSize
= NULL
;
929 if(VariablePayloadSize
== NULL
) {
930 return EFI_INVALID_PARAMETER
;
933 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
936 // Init the communicate buffer. The buffer data size is:
937 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
939 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
940 CommBuffer
= AllocateZeroPool (CommSize
);
941 if (CommBuffer
== NULL
) {
942 Status
= EFI_OUT_OF_RESOURCES
;
946 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) CommBuffer
;
947 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
948 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
950 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
951 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE
;
952 SmmGetPayloadSize
= (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*) SmmVariableFunctionHeader
->Data
;
957 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, CommBuffer
, &CommSize
);
958 ASSERT_EFI_ERROR (Status
);
960 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
961 if (EFI_ERROR (Status
)) {
966 // Get data from SMM.
968 *VariablePayloadSize
= SmmGetPayloadSize
->VariablePayloadSize
;
971 if (CommBuffer
!= NULL
) {
972 FreePool (CommBuffer
);
974 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
979 Initialize variable service and install Variable Architectural protocol.
981 @param[in] Event Event whose notification function is being invoked.
982 @param[in] Context Pointer to the notification function's context.
994 Status
= gBS
->LocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
995 if (EFI_ERROR (Status
)) {
999 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &mSmmCommunication
);
1000 ASSERT_EFI_ERROR (Status
);
1003 // Allocate memory for variable communicate buffer.
1005 Status
= GetVariablePayloadSize (&mVariableBufferPayloadSize
);
1006 ASSERT_EFI_ERROR (Status
);
1007 mVariableBufferSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ mVariableBufferPayloadSize
;
1008 mVariableBuffer
= AllocateRuntimePool (mVariableBufferSize
);
1009 ASSERT (mVariableBuffer
!= NULL
);
1012 // Save the buffer physical address used for SMM conmunication.
1014 mVariableBufferPhysical
= mVariableBuffer
;
1016 gRT
->GetVariable
= RuntimeServiceGetVariable
;
1017 gRT
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
1018 gRT
->SetVariable
= RuntimeServiceSetVariable
;
1019 gRT
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
1022 // Install the Variable Architectural Protocol on a new handle.
1024 Status
= gBS
->InstallProtocolInterface (
1026 &gEfiVariableArchProtocolGuid
,
1027 EFI_NATIVE_INTERFACE
,
1030 ASSERT_EFI_ERROR (Status
);
1032 mVariableLock
.RequestToLock
= VariableLockRequestToLock
;
1033 Status
= gBS
->InstallMultipleProtocolInterfaces (
1035 &gEdkiiVariableLockProtocolGuid
,
1039 ASSERT_EFI_ERROR (Status
);
1041 mVarCheck
.RegisterSetVariableCheckHandler
= VarCheckRegisterSetVariableCheckHandler
;
1042 mVarCheck
.VariablePropertySet
= VarCheckVariablePropertySet
;
1043 mVarCheck
.VariablePropertyGet
= VarCheckVariablePropertyGet
;
1044 Status
= gBS
->InstallMultipleProtocolInterfaces (
1046 &gEdkiiVarCheckProtocolGuid
,
1050 ASSERT_EFI_ERROR (Status
);
1052 gBS
->CloseEvent (Event
);
1057 SMM Non-Volatile variable write service is ready notify event handler.
1059 @param[in] Event Event whose notification function is being invoked.
1060 @param[in] Context Pointer to the notification function's context.
1065 SmmVariableWriteReady (
1074 // Check whether the protocol is installed or not.
1076 Status
= gBS
->LocateProtocol (&gSmmVariableWriteGuid
, NULL
, (VOID
**) &ProtocolOps
);
1077 if (EFI_ERROR (Status
)) {
1082 // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
1083 // Secure Boot Policy Variable change. Record their initial value.
1085 RecordSecureBootPolicyVarData();
1087 Status
= gBS
->InstallProtocolInterface (
1089 &gEfiVariableWriteArchProtocolGuid
,
1090 EFI_NATIVE_INTERFACE
,
1093 ASSERT_EFI_ERROR (Status
);
1095 gBS
->CloseEvent (Event
);
1100 Variable Driver main entry point. The Variable driver places the 4 EFI
1101 runtime services in the EFI System Table and installs arch protocols
1102 for variable read and write services being available. It also registers
1103 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1105 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1106 @param[in] SystemTable A pointer to the EFI System Table.
1108 @retval EFI_SUCCESS Variable service successfully initialized.
1113 VariableSmmRuntimeInitialize (
1114 IN EFI_HANDLE ImageHandle
,
1115 IN EFI_SYSTEM_TABLE
*SystemTable
1118 VOID
*SmmVariableRegistration
;
1119 VOID
*SmmVariableWriteRegistration
;
1120 EFI_EVENT OnReadyToBootEvent
;
1121 EFI_EVENT ExitBootServiceEvent
;
1122 EFI_EVENT LegacyBootEvent
;
1124 EfiInitializeLock (&mVariableServicesLock
, TPL_NOTIFY
);
1127 // Smm variable service is ready
1129 EfiCreateProtocolNotifyEvent (
1130 &gEfiSmmVariableProtocolGuid
,
1134 &SmmVariableRegistration
1138 // Smm Non-Volatile variable write service is ready
1140 EfiCreateProtocolNotifyEvent (
1141 &gSmmVariableWriteGuid
,
1143 SmmVariableWriteReady
,
1145 &SmmVariableWriteRegistration
1149 // Register the event to reclaim variable for OS usage.
1151 EfiCreateEventReadyToBootEx (
1159 // Register the event to inform SMM variable that it is at runtime.
1161 gBS
->CreateEventEx (
1166 &gEfiEventExitBootServicesGuid
,
1167 &ExitBootServiceEvent
1171 // Register the event to inform SMM variable that it is at runtime for legacy boot.
1172 // Reuse OnExitBootServices() here.
1174 EfiCreateEventLegacyBootEx(
1182 // Register the event to convert the pointer for runtime.
1184 gBS
->CreateEventEx (
1187 VariableAddressChangeEvent
,
1189 &gEfiEventVirtualAddressChangeGuid
,
1190 &mVirtualAddressChangeEvent