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 - 2015, 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.
28 #include <Protocol/VariableWrite.h>
29 #include <Protocol/Variable.h>
30 #include <Protocol/SmmCommunication.h>
31 #include <Protocol/SmmVariable.h>
32 #include <Protocol/VariableLock.h>
33 #include <Protocol/VarCheck.h>
35 #include <Library/UefiBootServicesTableLib.h>
36 #include <Library/UefiRuntimeServicesTableLib.h>
37 #include <Library/MemoryAllocationLib.h>
38 #include <Library/UefiDriverEntryPoint.h>
39 #include <Library/UefiRuntimeLib.h>
40 #include <Library/BaseMemoryLib.h>
41 #include <Library/DebugLib.h>
42 #include <Library/PcdLib.h>
43 #include <Library/UefiLib.h>
44 #include <Library/BaseLib.h>
46 #include <Guid/EventGroup.h>
47 #include <Guid/AuthenticatedVariableFormat.h>
48 #include <Guid/SmmVariableCommon.h>
50 EFI_HANDLE mHandle
= NULL
;
51 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
= NULL
;
52 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
53 EFI_SMM_COMMUNICATION_PROTOCOL
*mSmmCommunication
= NULL
;
54 UINT8
*mVariableBuffer
= NULL
;
55 UINT8
*mVariableBufferPhysical
= NULL
;
56 UINTN mVariableBufferSize
;
57 UINTN mVariableBufferPayloadSize
;
58 EFI_LOCK mVariableServicesLock
;
59 EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock
;
60 EDKII_VAR_CHECK_PROTOCOL mVarCheck
;
62 #define MAX_NV_VARIABLE_SIZE (MAX (MAX (PcdGet32 (PcdMaxVariableSize), \
63 PcdGet32 (PcdMaxAuthVariableSize)), \
64 PcdGet32 (PcdMaxHardwareErrorVariableSize)))
67 SecureBoot Hook for SetVariable.
69 @param[in] VariableName Name of Variable to be found.
70 @param[in] VendorGuid Variable vendor GUID.
76 IN CHAR16
*VariableName
,
77 IN EFI_GUID
*VendorGuid
81 Acquires lock only at boot time. Simply returns at runtime.
83 This is a temperary function that will be removed when
84 EfiAcquireLock() in UefiLib can handle the call in UEFI
85 Runtimer driver in RT phase.
86 It calls EfiAcquireLock() at boot time, and simply returns
89 @param Lock A pointer to the lock to acquire.
93 AcquireLockOnlyAtBootTime (
97 if (!EfiAtRuntime ()) {
98 EfiAcquireLock (Lock
);
103 Releases lock only at boot time. Simply returns at runtime.
105 This is a temperary function which will be removed when
106 EfiReleaseLock() in UefiLib can handle the call in UEFI
107 Runtimer driver in RT phase.
108 It calls EfiReleaseLock() at boot time and simply returns
111 @param Lock A pointer to the lock to release.
115 ReleaseLockOnlyAtBootTime (
119 if (!EfiAtRuntime ()) {
120 EfiReleaseLock (Lock
);
125 Initialize the communicate buffer using DataSize and Function.
127 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
130 Caution: This function may receive untrusted input.
131 The data size external input, so this function will validate it carefully to avoid buffer overflow.
133 @param[out] DataPtr Points to the data in the communicate buffer.
134 @param[in] DataSize The data size to send to SMM.
135 @param[in] Function The function number to initialize the communicate header.
137 @retval EFI_INVALID_PARAMETER The data size is too big.
138 @retval EFI_SUCCESS Find the specified variable.
142 InitCommunicateBuffer (
143 OUT VOID
**DataPtr OPTIONAL
,
148 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
149 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
152 if (DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
> mVariableBufferSize
) {
153 return EFI_INVALID_PARAMETER
;
156 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
157 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
158 SmmCommunicateHeader
->MessageLength
= DataSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
160 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
161 SmmVariableFunctionHeader
->Function
= Function
;
162 if (DataPtr
!= NULL
) {
163 *DataPtr
= SmmVariableFunctionHeader
->Data
;
171 Send the data in communicate buffer to SMM.
173 @param[in] DataSize This size of the function header and the data.
175 @retval EFI_SUCCESS Success is returned from the functin in SMM.
176 @retval Others Failure is returned from the function in SMM.
180 SendCommunicateBuffer (
186 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
187 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
189 CommSize
= DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
190 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, mVariableBufferPhysical
, &CommSize
);
191 ASSERT_EFI_ERROR (Status
);
193 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
194 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
195 return SmmVariableFunctionHeader
->ReturnStatus
;
199 Mark a variable that will become read-only after leaving the DXE phase of execution.
201 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
202 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
203 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
205 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
206 as pending to be read-only.
207 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
208 Or VariableName is an empty string.
209 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
210 already been signaled.
211 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
215 VariableLockRequestToLock (
216 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
217 IN CHAR16
*VariableName
,
218 IN EFI_GUID
*VendorGuid
222 UINTN VariableNameSize
;
224 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
226 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
227 return EFI_INVALID_PARAMETER
;
230 VariableNameSize
= StrSize (VariableName
);
231 VariableToLock
= NULL
;
234 // If VariableName exceeds SMM payload limit. Return failure
236 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
)) {
237 return EFI_INVALID_PARAMETER
;
240 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
243 // Init the communicate buffer. The buffer data size is:
244 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
246 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
) + VariableNameSize
;
247 Status
= InitCommunicateBuffer ((VOID
**) &VariableToLock
, PayloadSize
, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
);
248 if (EFI_ERROR (Status
)) {
251 ASSERT (VariableToLock
!= NULL
);
253 CopyGuid (&VariableToLock
->Guid
, VendorGuid
);
254 VariableToLock
->NameSize
= VariableNameSize
;
255 CopyMem (VariableToLock
->Name
, VariableName
, VariableToLock
->NameSize
);
260 Status
= SendCommunicateBuffer (PayloadSize
);
263 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
268 Register SetVariable check handler.
270 @param[in] Handler Pointer to check handler.
272 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
273 @retval EFI_INVALID_PARAMETER Handler is NULL.
274 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
275 already been signaled.
276 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
277 @retval EFI_UNSUPPORTED This interface is not implemented.
278 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
283 VarCheckRegisterSetVariableCheckHandler (
284 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
287 return EFI_UNSUPPORTED
;
291 Variable property set.
293 @param[in] Name Pointer to the variable name.
294 @param[in] Guid Pointer to the vendor GUID.
295 @param[in] VariableProperty Pointer to the input variable property.
297 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
298 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
299 or the fields of VariableProperty are not valid.
300 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
301 already been signaled.
302 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
307 VarCheckVariablePropertySet (
310 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
314 UINTN VariableNameSize
;
316 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
318 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
319 return EFI_INVALID_PARAMETER
;
322 if (VariableProperty
== NULL
) {
323 return EFI_INVALID_PARAMETER
;
326 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
327 return EFI_INVALID_PARAMETER
;
330 VariableNameSize
= StrSize (Name
);
331 CommVariableProperty
= NULL
;
334 // If VariableName exceeds SMM payload limit. Return failure
336 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
337 return EFI_INVALID_PARAMETER
;
340 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
343 // Init the communicate buffer. The buffer data size is:
344 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
346 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
347 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
);
348 if (EFI_ERROR (Status
)) {
351 ASSERT (CommVariableProperty
!= NULL
);
353 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
354 CopyMem (&CommVariableProperty
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
355 CommVariableProperty
->NameSize
= VariableNameSize
;
356 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
361 Status
= SendCommunicateBuffer (PayloadSize
);
364 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
369 Variable property get.
371 @param[in] Name Pointer to the variable name.
372 @param[in] Guid Pointer to the vendor GUID.
373 @param[out] VariableProperty Pointer to the output variable property.
375 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
376 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
377 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
382 VarCheckVariablePropertyGet (
385 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
389 UINTN VariableNameSize
;
391 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
393 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
394 return EFI_INVALID_PARAMETER
;
397 if (VariableProperty
== NULL
) {
398 return EFI_INVALID_PARAMETER
;
401 VariableNameSize
= StrSize (Name
);
402 CommVariableProperty
= NULL
;
405 // If VariableName exceeds SMM payload limit. Return failure
407 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
408 return EFI_INVALID_PARAMETER
;
411 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
414 // Init the communicate buffer. The buffer data size is:
415 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
417 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
418 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
);
419 if (EFI_ERROR (Status
)) {
422 ASSERT (CommVariableProperty
!= NULL
);
424 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
425 CommVariableProperty
->NameSize
= VariableNameSize
;
426 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
431 Status
= SendCommunicateBuffer (PayloadSize
);
432 if (Status
== EFI_SUCCESS
) {
433 CopyMem (VariableProperty
, &CommVariableProperty
->VariableProperty
, sizeof (*VariableProperty
));
437 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
442 This code finds variable in storage blocks (Volatile or Non-Volatile).
444 Caution: This function may receive untrusted input.
445 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
447 @param[in] VariableName Name of Variable to be found.
448 @param[in] VendorGuid Variable vendor GUID.
449 @param[out] Attributes Attribute value of the variable found.
450 @param[in, out] DataSize Size of Data found. If size is less than the
451 data, this value contains the required size.
452 @param[out] Data Data pointer.
454 @retval EFI_INVALID_PARAMETER Invalid parameter.
455 @retval EFI_SUCCESS Find the specified variable.
456 @retval EFI_NOT_FOUND Not found.
457 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
462 RuntimeServiceGetVariable (
463 IN CHAR16
*VariableName
,
464 IN EFI_GUID
*VendorGuid
,
465 OUT UINT32
*Attributes OPTIONAL
,
466 IN OUT UINTN
*DataSize
,
472 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
474 UINTN VariableNameSize
;
476 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
477 return EFI_INVALID_PARAMETER
;
480 TempDataSize
= *DataSize
;
481 VariableNameSize
= StrSize (VariableName
);
482 SmmVariableHeader
= NULL
;
485 // If VariableName exceeds SMM payload limit. Return failure
487 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
488 return EFI_INVALID_PARAMETER
;
491 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
494 // Init the communicate buffer. The buffer data size is:
495 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
497 if (TempDataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
) {
499 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
501 TempDataSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
;
503 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ TempDataSize
;
505 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_VARIABLE
);
506 if (EFI_ERROR (Status
)) {
509 ASSERT (SmmVariableHeader
!= NULL
);
511 CopyGuid (&SmmVariableHeader
->Guid
, VendorGuid
);
512 SmmVariableHeader
->DataSize
= TempDataSize
;
513 SmmVariableHeader
->NameSize
= VariableNameSize
;
514 if (Attributes
== NULL
) {
515 SmmVariableHeader
->Attributes
= 0;
517 SmmVariableHeader
->Attributes
= *Attributes
;
519 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
524 Status
= SendCommunicateBuffer (PayloadSize
);
527 // Get data from SMM.
529 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
531 // SMM CommBuffer DataSize can be a trimed value
532 // Only update DataSize when needed
534 *DataSize
= SmmVariableHeader
->DataSize
;
536 if (Attributes
!= NULL
) {
537 *Attributes
= SmmVariableHeader
->Attributes
;
540 if (EFI_ERROR (Status
)) {
545 CopyMem (Data
, (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, SmmVariableHeader
->DataSize
);
547 Status
= EFI_INVALID_PARAMETER
;
551 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
557 This code Finds the Next available variable.
559 @param[in, out] VariableNameSize Size of the variable name.
560 @param[in, out] VariableName Pointer to variable name.
561 @param[in, out] VendorGuid Variable Vendor Guid.
563 @retval EFI_INVALID_PARAMETER Invalid parameter.
564 @retval EFI_SUCCESS Find the specified variable.
565 @retval EFI_NOT_FOUND Not found.
566 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
571 RuntimeServiceGetNextVariableName (
572 IN OUT UINTN
*VariableNameSize
,
573 IN OUT CHAR16
*VariableName
,
574 IN OUT EFI_GUID
*VendorGuid
579 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*SmmGetNextVariableName
;
580 UINTN OutVariableNameSize
;
581 UINTN InVariableNameSize
;
583 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
584 return EFI_INVALID_PARAMETER
;
587 OutVariableNameSize
= *VariableNameSize
;
588 InVariableNameSize
= StrSize (VariableName
);
589 SmmGetNextVariableName
= NULL
;
592 // If input string exceeds SMM payload limit. Return failure
594 if (InVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
595 return EFI_INVALID_PARAMETER
;
598 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
601 // Init the communicate buffer. The buffer data size is:
602 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
604 if (OutVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
606 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
608 OutVariableNameSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
611 // Payload should be Guid + NameSize + MAX of Input & Output buffer
613 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + MAX (OutVariableNameSize
, InVariableNameSize
);
615 Status
= InitCommunicateBuffer ((VOID
**)&SmmGetNextVariableName
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
);
616 if (EFI_ERROR (Status
)) {
619 ASSERT (SmmGetNextVariableName
!= NULL
);
622 // SMM comm buffer->NameSize is buffer size for return string
624 SmmGetNextVariableName
->NameSize
= OutVariableNameSize
;
626 CopyGuid (&SmmGetNextVariableName
->Guid
, VendorGuid
);
630 CopyMem (SmmGetNextVariableName
->Name
, VariableName
, InVariableNameSize
);
631 if (OutVariableNameSize
> InVariableNameSize
) {
632 ZeroMem ((UINT8
*) SmmGetNextVariableName
->Name
+ InVariableNameSize
, OutVariableNameSize
- InVariableNameSize
);
638 Status
= SendCommunicateBuffer (PayloadSize
);
641 // Get data from SMM.
643 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
645 // SMM CommBuffer NameSize can be a trimed value
646 // Only update VariableNameSize when needed
648 *VariableNameSize
= SmmGetNextVariableName
->NameSize
;
650 if (EFI_ERROR (Status
)) {
654 CopyGuid (VendorGuid
, &SmmGetNextVariableName
->Guid
);
655 CopyMem (VariableName
, SmmGetNextVariableName
->Name
, SmmGetNextVariableName
->NameSize
);
658 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
663 This code sets variable in storage blocks (Volatile or Non-Volatile).
665 Caution: This function may receive untrusted input.
666 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
668 @param[in] VariableName Name of Variable to be found.
669 @param[in] VendorGuid Variable vendor GUID.
670 @param[in] Attributes Attribute value of the variable found
671 @param[in] DataSize Size of Data found. If size is less than the
672 data, this value contains the required size.
673 @param[in] Data Data pointer.
675 @retval EFI_INVALID_PARAMETER Invalid parameter.
676 @retval EFI_SUCCESS Set successfully.
677 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
678 @retval EFI_NOT_FOUND Not found.
679 @retval EFI_WRITE_PROTECTED Variable is read-only.
684 RuntimeServiceSetVariable (
685 IN CHAR16
*VariableName
,
686 IN EFI_GUID
*VendorGuid
,
687 IN UINT32 Attributes
,
694 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
695 UINTN VariableNameSize
;
698 // Check input parameters.
700 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
701 return EFI_INVALID_PARAMETER
;
704 if (DataSize
!= 0 && Data
== NULL
) {
705 return EFI_INVALID_PARAMETER
;
708 VariableNameSize
= StrSize (VariableName
);
709 SmmVariableHeader
= NULL
;
712 // If VariableName or DataSize exceeds SMM payload limit. Return failure
714 if ((VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
715 (DataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
)){
716 return EFI_INVALID_PARAMETER
;
719 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
722 // Init the communicate buffer. The buffer data size is:
723 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
725 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ DataSize
;
726 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_SET_VARIABLE
);
727 if (EFI_ERROR (Status
)) {
730 ASSERT (SmmVariableHeader
!= NULL
);
732 CopyGuid ((EFI_GUID
*) &SmmVariableHeader
->Guid
, VendorGuid
);
733 SmmVariableHeader
->DataSize
= DataSize
;
734 SmmVariableHeader
->NameSize
= VariableNameSize
;
735 SmmVariableHeader
->Attributes
= Attributes
;
736 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
737 CopyMem ((UINT8
*) SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, Data
, DataSize
);
742 Status
= SendCommunicateBuffer (PayloadSize
);
745 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
747 if (!EfiAtRuntime ()) {
748 if (!EFI_ERROR (Status
)) {
760 This code returns information about the EFI variables.
762 @param[in] Attributes Attributes bitmask to specify the type of variables
763 on which to return information.
764 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
765 for the EFI variables associated with the attributes specified.
766 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
767 for EFI variables associated with the attributes specified.
768 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
769 associated with the attributes specified.
771 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
772 @retval EFI_SUCCESS Query successfully.
773 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
778 RuntimeServiceQueryVariableInfo (
779 IN UINT32 Attributes
,
780 OUT UINT64
*MaximumVariableStorageSize
,
781 OUT UINT64
*RemainingVariableStorageSize
,
782 OUT UINT64
*MaximumVariableSize
787 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*SmmQueryVariableInfo
;
789 SmmQueryVariableInfo
= NULL
;
791 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
792 return EFI_INVALID_PARAMETER
;
795 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
798 // Init the communicate buffer. The buffer data size is:
799 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
801 PayloadSize
= sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
802 Status
= InitCommunicateBuffer ((VOID
**)&SmmQueryVariableInfo
, PayloadSize
, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
);
803 if (EFI_ERROR (Status
)) {
806 ASSERT (SmmQueryVariableInfo
!= NULL
);
808 SmmQueryVariableInfo
->Attributes
= Attributes
;
813 Status
= SendCommunicateBuffer (PayloadSize
);
814 if (EFI_ERROR (Status
)) {
819 // Get data from SMM.
821 *MaximumVariableSize
= SmmQueryVariableInfo
->MaximumVariableSize
;
822 *MaximumVariableStorageSize
= SmmQueryVariableInfo
->MaximumVariableStorageSize
;
823 *RemainingVariableStorageSize
= SmmQueryVariableInfo
->RemainingVariableStorageSize
;
826 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
832 Exit Boot Services Event notification handler.
834 Notify SMM variable driver about the event.
836 @param[in] Event Event whose notification function is being invoked.
837 @param[in] Context Pointer to the notification function's context.
848 // Init the communicate buffer. The buffer data size is:
849 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
851 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
);
856 SendCommunicateBuffer (0);
861 On Ready To Boot Services Event notification handler.
863 Notify SMM variable driver about the event.
865 @param[in] Event Event whose notification function is being invoked
866 @param[in] Context Pointer to the notification function's context
877 // Init the communicate buffer. The buffer data size is:
878 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
880 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT
);
885 SendCommunicateBuffer (0);
890 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
892 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
893 It convers pointer to new virtual address.
895 @param[in] Event Event whose notification function is being invoked.
896 @param[in] Context Pointer to the notification function's context.
901 VariableAddressChangeEvent (
906 EfiConvertPointer (0x0, (VOID
**) &mVariableBuffer
);
907 EfiConvertPointer (0x0, (VOID
**) &mSmmCommunication
);
912 Initialize variable service and install Variable Architectural protocol.
914 @param[in] Event Event whose notification function is being invoked.
915 @param[in] Context Pointer to the notification function's context.
927 Status
= gBS
->LocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
928 if (EFI_ERROR (Status
)) {
932 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &mSmmCommunication
);
933 ASSERT_EFI_ERROR (Status
);
936 // Allocate memory for variable communicate buffer.
938 mVariableBufferPayloadSize
= MAX_NV_VARIABLE_SIZE
+
939 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) - sizeof (VARIABLE_HEADER
);
940 mVariableBufferSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ mVariableBufferPayloadSize
;
941 mVariableBuffer
= AllocateRuntimePool (mVariableBufferSize
);
942 ASSERT (mVariableBuffer
!= NULL
);
945 // Save the buffer physical address used for SMM conmunication.
947 mVariableBufferPhysical
= mVariableBuffer
;
949 gRT
->GetVariable
= RuntimeServiceGetVariable
;
950 gRT
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
951 gRT
->SetVariable
= RuntimeServiceSetVariable
;
952 gRT
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
955 // Install the Variable Architectural Protocol on a new handle.
957 Status
= gBS
->InstallProtocolInterface (
959 &gEfiVariableArchProtocolGuid
,
960 EFI_NATIVE_INTERFACE
,
963 ASSERT_EFI_ERROR (Status
);
968 SMM Non-Volatile variable write service is ready notify event handler.
970 @param[in] Event Event whose notification function is being invoked.
971 @param[in] Context Pointer to the notification function's context.
976 SmmVariableWriteReady (
985 // Check whether the protocol is installed or not.
987 Status
= gBS
->LocateProtocol (&gSmmVariableWriteGuid
, NULL
, (VOID
**) &ProtocolOps
);
988 if (EFI_ERROR (Status
)) {
992 Status
= gBS
->InstallProtocolInterface (
994 &gEfiVariableWriteArchProtocolGuid
,
995 EFI_NATIVE_INTERFACE
,
998 ASSERT_EFI_ERROR (Status
);
1003 Variable Driver main entry point. The Variable driver places the 4 EFI
1004 runtime services in the EFI System Table and installs arch protocols
1005 for variable read and write services being available. It also registers
1006 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1008 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1009 @param[in] SystemTable A pointer to the EFI System Table.
1011 @retval EFI_SUCCESS Variable service successfully initialized.
1016 VariableSmmRuntimeInitialize (
1017 IN EFI_HANDLE ImageHandle
,
1018 IN EFI_SYSTEM_TABLE
*SystemTable
1022 VOID
*SmmVariableRegistration
;
1023 VOID
*SmmVariableWriteRegistration
;
1024 EFI_EVENT OnReadyToBootEvent
;
1025 EFI_EVENT ExitBootServiceEvent
;
1026 EFI_EVENT LegacyBootEvent
;
1028 EfiInitializeLock (&mVariableServicesLock
, TPL_NOTIFY
);
1030 mVariableLock
.RequestToLock
= VariableLockRequestToLock
;
1031 Status
= gBS
->InstallMultipleProtocolInterfaces (
1033 &gEdkiiVariableLockProtocolGuid
,
1037 ASSERT_EFI_ERROR (Status
);
1039 mVarCheck
.RegisterSetVariableCheckHandler
= VarCheckRegisterSetVariableCheckHandler
;
1040 mVarCheck
.VariablePropertySet
= VarCheckVariablePropertySet
;
1041 mVarCheck
.VariablePropertyGet
= VarCheckVariablePropertyGet
;
1042 Status
= gBS
->InstallMultipleProtocolInterfaces (
1044 &gEdkiiVarCheckProtocolGuid
,
1048 ASSERT_EFI_ERROR (Status
);
1051 // Smm variable service is ready
1053 EfiCreateProtocolNotifyEvent (
1054 &gEfiSmmVariableProtocolGuid
,
1058 &SmmVariableRegistration
1062 // Smm Non-Volatile variable write service is ready
1064 EfiCreateProtocolNotifyEvent (
1065 &gSmmVariableWriteGuid
,
1067 SmmVariableWriteReady
,
1069 &SmmVariableWriteRegistration
1073 // Register the event to reclaim variable for OS usage.
1075 EfiCreateEventReadyToBootEx (
1083 // Register the event to inform SMM variable that it is at runtime.
1085 gBS
->CreateEventEx (
1090 &gEfiEventExitBootServicesGuid
,
1091 &ExitBootServiceEvent
1095 // Register the event to inform SMM variable that it is at runtime for legacy boot.
1096 // Reuse OnExitBootServices() here.
1098 EfiCreateEventLegacyBootEx(
1106 // Register the event to convert the pointer for runtime.
1108 gBS
->CreateEventEx (
1111 VariableAddressChangeEvent
,
1113 &gEfiEventVirtualAddressChangeGuid
,
1114 &mVirtualAddressChangeEvent