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
;
63 SecureBoot Hook for SetVariable.
65 @param[in] VariableName Name of Variable to be found.
66 @param[in] VendorGuid Variable vendor GUID.
72 IN CHAR16
*VariableName
,
73 IN EFI_GUID
*VendorGuid
77 Acquires lock only at boot time. Simply returns at runtime.
79 This is a temperary function that will be removed when
80 EfiAcquireLock() in UefiLib can handle the call in UEFI
81 Runtimer driver in RT phase.
82 It calls EfiAcquireLock() at boot time, and simply returns
85 @param Lock A pointer to the lock to acquire.
89 AcquireLockOnlyAtBootTime (
93 if (!EfiAtRuntime ()) {
94 EfiAcquireLock (Lock
);
99 Releases lock only at boot time. Simply returns at runtime.
101 This is a temperary function which will be removed when
102 EfiReleaseLock() in UefiLib can handle the call in UEFI
103 Runtimer driver in RT phase.
104 It calls EfiReleaseLock() at boot time and simply returns
107 @param Lock A pointer to the lock to release.
111 ReleaseLockOnlyAtBootTime (
115 if (!EfiAtRuntime ()) {
116 EfiReleaseLock (Lock
);
121 Initialize the communicate buffer using DataSize and Function.
123 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
126 Caution: This function may receive untrusted input.
127 The data size external input, so this function will validate it carefully to avoid buffer overflow.
129 @param[out] DataPtr Points to the data in the communicate buffer.
130 @param[in] DataSize The data size to send to SMM.
131 @param[in] Function The function number to initialize the communicate header.
133 @retval EFI_INVALID_PARAMETER The data size is too big.
134 @retval EFI_SUCCESS Find the specified variable.
138 InitCommunicateBuffer (
139 OUT VOID
**DataPtr OPTIONAL
,
144 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
145 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
148 if (DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
> mVariableBufferSize
) {
149 return EFI_INVALID_PARAMETER
;
152 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
153 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
154 SmmCommunicateHeader
->MessageLength
= DataSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
156 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
157 SmmVariableFunctionHeader
->Function
= Function
;
158 if (DataPtr
!= NULL
) {
159 *DataPtr
= SmmVariableFunctionHeader
->Data
;
167 Send the data in communicate buffer to SMM.
169 @param[in] DataSize This size of the function header and the data.
171 @retval EFI_SUCCESS Success is returned from the functin in SMM.
172 @retval Others Failure is returned from the function in SMM.
176 SendCommunicateBuffer (
182 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
183 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
185 CommSize
= DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
186 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, mVariableBufferPhysical
, &CommSize
);
187 ASSERT_EFI_ERROR (Status
);
189 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
190 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
191 return SmmVariableFunctionHeader
->ReturnStatus
;
195 Mark a variable that will become read-only after leaving the DXE phase of execution.
197 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
198 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
199 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
201 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
202 as pending to be read-only.
203 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
204 Or VariableName is an empty string.
205 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
206 already been signaled.
207 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
211 VariableLockRequestToLock (
212 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
213 IN CHAR16
*VariableName
,
214 IN EFI_GUID
*VendorGuid
218 UINTN VariableNameSize
;
220 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
222 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
223 return EFI_INVALID_PARAMETER
;
226 VariableNameSize
= StrSize (VariableName
);
227 VariableToLock
= NULL
;
230 // If VariableName exceeds SMM payload limit. Return failure
232 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
)) {
233 return EFI_INVALID_PARAMETER
;
236 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
239 // Init the communicate buffer. The buffer data size is:
240 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
242 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
) + VariableNameSize
;
243 Status
= InitCommunicateBuffer ((VOID
**) &VariableToLock
, PayloadSize
, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
);
244 if (EFI_ERROR (Status
)) {
247 ASSERT (VariableToLock
!= NULL
);
249 CopyGuid (&VariableToLock
->Guid
, VendorGuid
);
250 VariableToLock
->NameSize
= VariableNameSize
;
251 CopyMem (VariableToLock
->Name
, VariableName
, VariableToLock
->NameSize
);
256 Status
= SendCommunicateBuffer (PayloadSize
);
259 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
264 Register SetVariable check handler.
266 @param[in] Handler Pointer to check handler.
268 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
269 @retval EFI_INVALID_PARAMETER Handler is NULL.
270 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
271 already been signaled.
272 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
273 @retval EFI_UNSUPPORTED This interface is not implemented.
274 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
279 VarCheckRegisterSetVariableCheckHandler (
280 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
283 return EFI_UNSUPPORTED
;
287 Variable property set.
289 @param[in] Name Pointer to the variable name.
290 @param[in] Guid Pointer to the vendor GUID.
291 @param[in] VariableProperty Pointer to the input variable property.
293 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
294 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
295 or the fields of VariableProperty are not valid.
296 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
297 already been signaled.
298 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
303 VarCheckVariablePropertySet (
306 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
310 UINTN VariableNameSize
;
312 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
314 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
315 return EFI_INVALID_PARAMETER
;
318 if (VariableProperty
== NULL
) {
319 return EFI_INVALID_PARAMETER
;
322 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
323 return EFI_INVALID_PARAMETER
;
326 VariableNameSize
= StrSize (Name
);
327 CommVariableProperty
= NULL
;
330 // If VariableName exceeds SMM payload limit. Return failure
332 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
333 return EFI_INVALID_PARAMETER
;
336 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
339 // Init the communicate buffer. The buffer data size is:
340 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
342 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
343 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
);
344 if (EFI_ERROR (Status
)) {
347 ASSERT (CommVariableProperty
!= NULL
);
349 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
350 CopyMem (&CommVariableProperty
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
351 CommVariableProperty
->NameSize
= VariableNameSize
;
352 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
357 Status
= SendCommunicateBuffer (PayloadSize
);
360 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
365 Variable property get.
367 @param[in] Name Pointer to the variable name.
368 @param[in] Guid Pointer to the vendor GUID.
369 @param[out] VariableProperty Pointer to the output variable property.
371 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
372 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
373 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
378 VarCheckVariablePropertyGet (
381 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
385 UINTN VariableNameSize
;
387 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
389 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
390 return EFI_INVALID_PARAMETER
;
393 if (VariableProperty
== NULL
) {
394 return EFI_INVALID_PARAMETER
;
397 VariableNameSize
= StrSize (Name
);
398 CommVariableProperty
= NULL
;
401 // If VariableName exceeds SMM payload limit. Return failure
403 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
404 return EFI_INVALID_PARAMETER
;
407 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
410 // Init the communicate buffer. The buffer data size is:
411 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
413 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
414 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
);
415 if (EFI_ERROR (Status
)) {
418 ASSERT (CommVariableProperty
!= NULL
);
420 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
421 CommVariableProperty
->NameSize
= VariableNameSize
;
422 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
427 Status
= SendCommunicateBuffer (PayloadSize
);
428 if (Status
== EFI_SUCCESS
) {
429 CopyMem (VariableProperty
, &CommVariableProperty
->VariableProperty
, sizeof (*VariableProperty
));
433 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
438 This code finds variable in storage blocks (Volatile or Non-Volatile).
440 Caution: This function may receive untrusted input.
441 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
443 @param[in] VariableName Name of Variable to be found.
444 @param[in] VendorGuid Variable vendor GUID.
445 @param[out] Attributes Attribute value of the variable found.
446 @param[in, out] DataSize Size of Data found. If size is less than the
447 data, this value contains the required size.
448 @param[out] Data Data pointer.
450 @retval EFI_INVALID_PARAMETER Invalid parameter.
451 @retval EFI_SUCCESS Find the specified variable.
452 @retval EFI_NOT_FOUND Not found.
453 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
458 RuntimeServiceGetVariable (
459 IN CHAR16
*VariableName
,
460 IN EFI_GUID
*VendorGuid
,
461 OUT UINT32
*Attributes OPTIONAL
,
462 IN OUT UINTN
*DataSize
,
468 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
470 UINTN VariableNameSize
;
472 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
473 return EFI_INVALID_PARAMETER
;
476 TempDataSize
= *DataSize
;
477 VariableNameSize
= StrSize (VariableName
);
478 SmmVariableHeader
= NULL
;
481 // If VariableName exceeds SMM payload limit. Return failure
483 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
484 return EFI_INVALID_PARAMETER
;
487 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
490 // Init the communicate buffer. The buffer data size is:
491 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
493 if (TempDataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
) {
495 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
497 TempDataSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
;
499 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ TempDataSize
;
501 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_VARIABLE
);
502 if (EFI_ERROR (Status
)) {
505 ASSERT (SmmVariableHeader
!= NULL
);
507 CopyGuid (&SmmVariableHeader
->Guid
, VendorGuid
);
508 SmmVariableHeader
->DataSize
= TempDataSize
;
509 SmmVariableHeader
->NameSize
= VariableNameSize
;
510 if (Attributes
== NULL
) {
511 SmmVariableHeader
->Attributes
= 0;
513 SmmVariableHeader
->Attributes
= *Attributes
;
515 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
520 Status
= SendCommunicateBuffer (PayloadSize
);
523 // Get data from SMM.
525 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
527 // SMM CommBuffer DataSize can be a trimed value
528 // Only update DataSize when needed
530 *DataSize
= SmmVariableHeader
->DataSize
;
532 if (Attributes
!= NULL
) {
533 *Attributes
= SmmVariableHeader
->Attributes
;
536 if (EFI_ERROR (Status
)) {
541 CopyMem (Data
, (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, SmmVariableHeader
->DataSize
);
543 Status
= EFI_INVALID_PARAMETER
;
547 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
553 This code Finds the Next available variable.
555 @param[in, out] VariableNameSize Size of the variable name.
556 @param[in, out] VariableName Pointer to variable name.
557 @param[in, out] VendorGuid Variable Vendor Guid.
559 @retval EFI_INVALID_PARAMETER Invalid parameter.
560 @retval EFI_SUCCESS Find the specified variable.
561 @retval EFI_NOT_FOUND Not found.
562 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
567 RuntimeServiceGetNextVariableName (
568 IN OUT UINTN
*VariableNameSize
,
569 IN OUT CHAR16
*VariableName
,
570 IN OUT EFI_GUID
*VendorGuid
575 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*SmmGetNextVariableName
;
576 UINTN OutVariableNameSize
;
577 UINTN InVariableNameSize
;
579 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
580 return EFI_INVALID_PARAMETER
;
583 OutVariableNameSize
= *VariableNameSize
;
584 InVariableNameSize
= StrSize (VariableName
);
585 SmmGetNextVariableName
= NULL
;
588 // If input string exceeds SMM payload limit. Return failure
590 if (InVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
591 return EFI_INVALID_PARAMETER
;
594 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
597 // Init the communicate buffer. The buffer data size is:
598 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
600 if (OutVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
602 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
604 OutVariableNameSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
607 // Payload should be Guid + NameSize + MAX of Input & Output buffer
609 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + MAX (OutVariableNameSize
, InVariableNameSize
);
611 Status
= InitCommunicateBuffer ((VOID
**)&SmmGetNextVariableName
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
);
612 if (EFI_ERROR (Status
)) {
615 ASSERT (SmmGetNextVariableName
!= NULL
);
618 // SMM comm buffer->NameSize is buffer size for return string
620 SmmGetNextVariableName
->NameSize
= OutVariableNameSize
;
622 CopyGuid (&SmmGetNextVariableName
->Guid
, VendorGuid
);
626 CopyMem (SmmGetNextVariableName
->Name
, VariableName
, InVariableNameSize
);
627 if (OutVariableNameSize
> InVariableNameSize
) {
628 ZeroMem ((UINT8
*) SmmGetNextVariableName
->Name
+ InVariableNameSize
, OutVariableNameSize
- InVariableNameSize
);
634 Status
= SendCommunicateBuffer (PayloadSize
);
637 // Get data from SMM.
639 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
641 // SMM CommBuffer NameSize can be a trimed value
642 // Only update VariableNameSize when needed
644 *VariableNameSize
= SmmGetNextVariableName
->NameSize
;
646 if (EFI_ERROR (Status
)) {
650 CopyGuid (VendorGuid
, &SmmGetNextVariableName
->Guid
);
651 CopyMem (VariableName
, SmmGetNextVariableName
->Name
, SmmGetNextVariableName
->NameSize
);
654 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
659 This code sets variable in storage blocks (Volatile or Non-Volatile).
661 Caution: This function may receive untrusted input.
662 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
664 @param[in] VariableName Name of Variable to be found.
665 @param[in] VendorGuid Variable vendor GUID.
666 @param[in] Attributes Attribute value of the variable found
667 @param[in] DataSize Size of Data found. If size is less than the
668 data, this value contains the required size.
669 @param[in] Data Data pointer.
671 @retval EFI_INVALID_PARAMETER Invalid parameter.
672 @retval EFI_SUCCESS Set successfully.
673 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
674 @retval EFI_NOT_FOUND Not found.
675 @retval EFI_WRITE_PROTECTED Variable is read-only.
680 RuntimeServiceSetVariable (
681 IN CHAR16
*VariableName
,
682 IN EFI_GUID
*VendorGuid
,
683 IN UINT32 Attributes
,
690 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
691 UINTN VariableNameSize
;
694 // Check input parameters.
696 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
697 return EFI_INVALID_PARAMETER
;
700 if (DataSize
!= 0 && Data
== NULL
) {
701 return EFI_INVALID_PARAMETER
;
704 VariableNameSize
= StrSize (VariableName
);
705 SmmVariableHeader
= NULL
;
708 // If VariableName or DataSize exceeds SMM payload limit. Return failure
710 if ((VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
711 (DataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
)){
712 return EFI_INVALID_PARAMETER
;
715 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
718 // Init the communicate buffer. The buffer data size is:
719 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
721 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ DataSize
;
722 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_SET_VARIABLE
);
723 if (EFI_ERROR (Status
)) {
726 ASSERT (SmmVariableHeader
!= NULL
);
728 CopyGuid ((EFI_GUID
*) &SmmVariableHeader
->Guid
, VendorGuid
);
729 SmmVariableHeader
->DataSize
= DataSize
;
730 SmmVariableHeader
->NameSize
= VariableNameSize
;
731 SmmVariableHeader
->Attributes
= Attributes
;
732 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
733 CopyMem ((UINT8
*) SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, Data
, DataSize
);
738 Status
= SendCommunicateBuffer (PayloadSize
);
741 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
743 if (!EfiAtRuntime ()) {
744 if (!EFI_ERROR (Status
)) {
756 This code returns information about the EFI variables.
758 @param[in] Attributes Attributes bitmask to specify the type of variables
759 on which to return information.
760 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
761 for the EFI variables associated with the attributes specified.
762 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
763 for EFI variables associated with the attributes specified.
764 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
765 associated with the attributes specified.
767 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
768 @retval EFI_SUCCESS Query successfully.
769 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
774 RuntimeServiceQueryVariableInfo (
775 IN UINT32 Attributes
,
776 OUT UINT64
*MaximumVariableStorageSize
,
777 OUT UINT64
*RemainingVariableStorageSize
,
778 OUT UINT64
*MaximumVariableSize
783 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*SmmQueryVariableInfo
;
785 SmmQueryVariableInfo
= NULL
;
787 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
788 return EFI_INVALID_PARAMETER
;
791 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
794 // Init the communicate buffer. The buffer data size is:
795 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
797 PayloadSize
= sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
798 Status
= InitCommunicateBuffer ((VOID
**)&SmmQueryVariableInfo
, PayloadSize
, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
);
799 if (EFI_ERROR (Status
)) {
802 ASSERT (SmmQueryVariableInfo
!= NULL
);
804 SmmQueryVariableInfo
->Attributes
= Attributes
;
809 Status
= SendCommunicateBuffer (PayloadSize
);
810 if (EFI_ERROR (Status
)) {
815 // Get data from SMM.
817 *MaximumVariableSize
= SmmQueryVariableInfo
->MaximumVariableSize
;
818 *MaximumVariableStorageSize
= SmmQueryVariableInfo
->MaximumVariableStorageSize
;
819 *RemainingVariableStorageSize
= SmmQueryVariableInfo
->RemainingVariableStorageSize
;
822 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
828 Exit Boot Services Event notification handler.
830 Notify SMM variable driver about the event.
832 @param[in] Event Event whose notification function is being invoked.
833 @param[in] Context Pointer to the notification function's context.
844 // Init the communicate buffer. The buffer data size is:
845 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
847 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
);
852 SendCommunicateBuffer (0);
857 On Ready To Boot Services Event notification handler.
859 Notify SMM variable driver about the event.
861 @param[in] Event Event whose notification function is being invoked
862 @param[in] Context Pointer to the notification function's context
873 // Init the communicate buffer. The buffer data size is:
874 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
876 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT
);
881 SendCommunicateBuffer (0);
886 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
888 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
889 It convers pointer to new virtual address.
891 @param[in] Event Event whose notification function is being invoked.
892 @param[in] Context Pointer to the notification function's context.
897 VariableAddressChangeEvent (
902 EfiConvertPointer (0x0, (VOID
**) &mVariableBuffer
);
903 EfiConvertPointer (0x0, (VOID
**) &mSmmCommunication
);
908 Initialize variable service and install Variable Architectural protocol.
910 @param[in] Event Event whose notification function is being invoked.
911 @param[in] Context Pointer to the notification function's context.
923 Status
= gBS
->LocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
924 if (EFI_ERROR (Status
)) {
928 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &mSmmCommunication
);
929 ASSERT_EFI_ERROR (Status
);
932 // Allocate memory for variable communicate buffer.
934 mVariableBufferPayloadSize
= MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
)) +
935 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) - sizeof (VARIABLE_HEADER
);
936 mVariableBufferSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ mVariableBufferPayloadSize
;
937 mVariableBuffer
= AllocateRuntimePool (mVariableBufferSize
);
938 ASSERT (mVariableBuffer
!= NULL
);
941 // Save the buffer physical address used for SMM conmunication.
943 mVariableBufferPhysical
= mVariableBuffer
;
945 gRT
->GetVariable
= RuntimeServiceGetVariable
;
946 gRT
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
947 gRT
->SetVariable
= RuntimeServiceSetVariable
;
948 gRT
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
951 // Install the Variable Architectural Protocol on a new handle.
953 Status
= gBS
->InstallProtocolInterface (
955 &gEfiVariableArchProtocolGuid
,
956 EFI_NATIVE_INTERFACE
,
959 ASSERT_EFI_ERROR (Status
);
964 SMM Non-Volatile variable write service is ready notify event handler.
966 @param[in] Event Event whose notification function is being invoked.
967 @param[in] Context Pointer to the notification function's context.
972 SmmVariableWriteReady (
981 // Check whether the protocol is installed or not.
983 Status
= gBS
->LocateProtocol (&gSmmVariableWriteGuid
, NULL
, (VOID
**) &ProtocolOps
);
984 if (EFI_ERROR (Status
)) {
988 Status
= gBS
->InstallProtocolInterface (
990 &gEfiVariableWriteArchProtocolGuid
,
991 EFI_NATIVE_INTERFACE
,
994 ASSERT_EFI_ERROR (Status
);
999 Variable Driver main entry point. The Variable driver places the 4 EFI
1000 runtime services in the EFI System Table and installs arch protocols
1001 for variable read and write services being available. It also registers
1002 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1004 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1005 @param[in] SystemTable A pointer to the EFI System Table.
1007 @retval EFI_SUCCESS Variable service successfully initialized.
1012 VariableSmmRuntimeInitialize (
1013 IN EFI_HANDLE ImageHandle
,
1014 IN EFI_SYSTEM_TABLE
*SystemTable
1018 VOID
*SmmVariableRegistration
;
1019 VOID
*SmmVariableWriteRegistration
;
1020 EFI_EVENT OnReadyToBootEvent
;
1021 EFI_EVENT ExitBootServiceEvent
;
1022 EFI_EVENT LegacyBootEvent
;
1024 EfiInitializeLock (&mVariableServicesLock
, TPL_NOTIFY
);
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
);
1047 // Smm variable service is ready
1049 EfiCreateProtocolNotifyEvent (
1050 &gEfiSmmVariableProtocolGuid
,
1054 &SmmVariableRegistration
1058 // Smm Non-Volatile variable write service is ready
1060 EfiCreateProtocolNotifyEvent (
1061 &gSmmVariableWriteGuid
,
1063 SmmVariableWriteReady
,
1065 &SmmVariableWriteRegistration
1069 // Register the event to reclaim variable for OS usage.
1071 EfiCreateEventReadyToBootEx (
1079 // Register the event to inform SMM variable that it is at runtime.
1081 gBS
->CreateEventEx (
1086 &gEfiEventExitBootServicesGuid
,
1087 &ExitBootServiceEvent
1091 // Register the event to inform SMM variable that it is at runtime for legacy boot.
1092 // Reuse OnExitBootServices() here.
1094 EfiCreateEventLegacyBootEx(
1102 // Register the event to convert the pointer for runtime.
1104 gBS
->CreateEventEx (
1107 VariableAddressChangeEvent
,
1109 &gEfiEventVirtualAddressChangeGuid
,
1110 &mVirtualAddressChangeEvent