2 The sample implementation for SMM variable protocol. And this driver
3 implements an SMI handler to communicate with the DXE runtime driver
4 to provide variable services.
6 Caution: This module requires additional review when modified.
7 This driver will have external input - variable data and communicate buffer in SMM mode.
8 This external input must be validated carefully to avoid security issue like
9 buffer overflow, integer overflow.
11 SmmVariableHandler() will receive untrusted input and do basic validation.
13 Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
14 VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
15 SmmVariableGetStatistics() should also do validation based on its own knowledge.
17 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>
18 This program and the accompanying materials
19 are licensed and made available under the terms and conditions of the BSD License
20 which accompanies this distribution. The full text of the license may be found at
21 http://opensource.org/licenses/bsd-license.php
23 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
24 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
28 #include <Protocol/SmmVariable.h>
29 #include <Protocol/SmmFirmwareVolumeBlock.h>
30 #include <Protocol/SmmFaultTolerantWrite.h>
31 #include <Protocol/SmmAccess2.h>
32 #include <Protocol/SmmEndOfDxe.h>
33 #include <Protocol/SmmVarCheck.h>
35 #include <Library/SmmServicesTableLib.h>
36 #include <Library/SmmMemLib.h>
38 #include <Guid/AuthenticatedVariableFormat.h>
39 #include <Guid/SmmVariableCommon.h>
42 extern VARIABLE_INFO_ENTRY
*gVariableInfo
;
43 EFI_HANDLE mSmmVariableHandle
= NULL
;
44 EFI_HANDLE mVariableHandle
= NULL
;
45 BOOLEAN mAtRuntime
= FALSE
;
46 EFI_GUID mZeroGuid
= {0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0}};
47 UINT8
*mVariableBufferPayload
= NULL
;
48 UINTN mVariableBufferPayloadSize
;
49 extern BOOLEAN mEndOfDxe
;
50 extern BOOLEAN mEnableLocking
;
53 SecureBoot Hook for SetVariable.
55 @param[in] VariableName Name of Variable to be found.
56 @param[in] VendorGuid Variable vendor GUID.
62 IN CHAR16
*VariableName
,
63 IN EFI_GUID
*VendorGuid
71 This code sets variable in storage blocks (Volatile or Non-Volatile).
73 @param VariableName Name of Variable to be found.
74 @param VendorGuid Variable vendor GUID.
75 @param Attributes Attribute value of the variable found
76 @param DataSize Size of Data found. If size is less than the
77 data, this value contains the required size.
78 @param Data Data pointer.
80 @return EFI_INVALID_PARAMETER Invalid parameter.
81 @return EFI_SUCCESS Set successfully.
82 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
83 @return EFI_NOT_FOUND Not found.
84 @return EFI_WRITE_PROTECTED Variable is read-only.
89 SmmVariableSetVariable (
90 IN CHAR16
*VariableName
,
91 IN EFI_GUID
*VendorGuid
,
100 // Disable write protection when the calling SetVariable() through EFI_SMM_VARIABLE_PROTOCOL.
102 mEnableLocking
= FALSE
;
103 Status
= VariableServiceSetVariable (
110 mEnableLocking
= TRUE
;
114 EFI_SMM_VARIABLE_PROTOCOL gSmmVariable
= {
115 VariableServiceGetVariable
,
116 VariableServiceGetNextVariableName
,
117 SmmVariableSetVariable
,
118 VariableServiceQueryVariableInfo
121 EDKII_SMM_VAR_CHECK_PROTOCOL mSmmVarCheck
= { VarCheckRegisterSetVariableCheckHandler
,
122 VarCheckVariablePropertySet
,
123 VarCheckVariablePropertyGet
};
126 Return TRUE if ExitBootServices () has been called.
128 @retval TRUE If ExitBootServices () has been called.
139 Initializes a basic mutual exclusion lock.
141 This function initializes a basic mutual exclusion lock to the released state
142 and returns the lock. Each lock provides mutual exclusion access at its task
143 priority level. Since there is no preemption or multiprocessor support in EFI,
144 acquiring the lock only consists of raising to the locks TPL.
145 If Lock is NULL, then ASSERT().
146 If Priority is not a valid TPL value, then ASSERT().
148 @param Lock A pointer to the lock data structure to initialize.
149 @param Priority EFI TPL is associated with the lock.
156 IN OUT EFI_LOCK
*Lock
,
164 Acquires lock only at boot time. Simply returns at runtime.
166 This is a temperary function that will be removed when
167 EfiAcquireLock() in UefiLib can handle the call in UEFI
168 Runtimer driver in RT phase.
169 It calls EfiAcquireLock() at boot time, and simply returns
172 @param Lock A pointer to the lock to acquire.
176 AcquireLockOnlyAtBootTime (
185 Releases lock only at boot time. Simply returns at runtime.
187 This is a temperary function which will be removed when
188 EfiReleaseLock() in UefiLib can handle the call in UEFI
189 Runtimer driver in RT phase.
190 It calls EfiReleaseLock() at boot time and simply returns
193 @param Lock A pointer to the lock to release.
197 ReleaseLockOnlyAtBootTime (
205 Retrive the SMM Fault Tolerent Write protocol interface.
207 @param[out] FtwProtocol The interface of SMM Ftw protocol
209 @retval EFI_SUCCESS The SMM FTW protocol instance was found and returned in FtwProtocol.
210 @retval EFI_NOT_FOUND The SMM FTW protocol instance was not found.
211 @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
216 OUT VOID
**FtwProtocol
222 // Locate Smm Fault Tolerent Write protocol
224 Status
= gSmst
->SmmLocateProtocol (
225 &gEfiSmmFaultTolerantWriteProtocolGuid
,
234 Retrive the SMM FVB protocol interface by HANDLE.
236 @param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for
237 reading, writing, and erasing the target block.
238 @param[out] FvBlock The interface of SMM FVB protocol
240 @retval EFI_SUCCESS The interface information for the specified protocol was returned.
241 @retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol.
242 @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
247 IN EFI_HANDLE FvBlockHandle
,
248 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvBlock
252 // To get the SMM FVB protocol interface on the handle
254 return gSmst
->SmmHandleProtocol (
256 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
263 Function returns an array of handles that support the SMM FVB protocol
264 in a buffer allocated from pool.
266 @param[out] NumberHandles The number of handles returned in Buffer.
267 @param[out] Buffer A pointer to the buffer to return the requested
268 array of handles that support SMM FVB protocol.
270 @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
271 handles in Buffer was returned in NumberHandles.
272 @retval EFI_NOT_FOUND No SMM FVB handle was found.
273 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
274 @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
278 GetFvbCountAndBuffer (
279 OUT UINTN
*NumberHandles
,
280 OUT EFI_HANDLE
**Buffer
286 if ((NumberHandles
== NULL
) || (Buffer
== NULL
)) {
287 return EFI_INVALID_PARAMETER
;
293 Status
= gSmst
->SmmLocateHandle (
295 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
300 if (EFI_ERROR(Status
) && Status
!= EFI_BUFFER_TOO_SMALL
) {
301 return EFI_NOT_FOUND
;
304 *Buffer
= AllocatePool (BufferSize
);
305 if (*Buffer
== NULL
) {
306 return EFI_OUT_OF_RESOURCES
;
309 Status
= gSmst
->SmmLocateHandle (
311 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
317 *NumberHandles
= BufferSize
/ sizeof(EFI_HANDLE
);
318 if (EFI_ERROR(Status
)) {
329 Get the variable statistics information from the information buffer pointed by gVariableInfo.
331 Caution: This function may be invoked at SMM runtime.
332 InfoEntry and InfoSize are external input. Care must be taken to make sure not security issue at runtime.
334 @param[in, out] InfoEntry A pointer to the buffer of variable information entry.
335 On input, point to the variable information returned last time. if
336 InfoEntry->VendorGuid is zero, return the first information.
337 On output, point to the next variable information.
338 @param[in, out] InfoSize On input, the size of the variable information buffer.
339 On output, the returned variable information size.
341 @retval EFI_SUCCESS The variable information is found and returned successfully.
342 @retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The
343 PcdVariableCollectStatistics should be set TRUE to support it.
344 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information.
345 @retval EFI_INVALID_PARAMETER Input parameter is invalid.
349 SmmVariableGetStatistics (
350 IN OUT VARIABLE_INFO_ENTRY
*InfoEntry
,
351 IN OUT UINTN
*InfoSize
354 VARIABLE_INFO_ENTRY
*VariableInfo
;
356 UINTN StatisticsInfoSize
;
360 if (InfoEntry
== NULL
) {
361 return EFI_INVALID_PARAMETER
;
364 VariableInfo
= gVariableInfo
;
365 if (VariableInfo
== NULL
) {
366 return EFI_UNSUPPORTED
;
369 StatisticsInfoSize
= sizeof (VARIABLE_INFO_ENTRY
) + StrSize (VariableInfo
->Name
);
370 if (*InfoSize
< StatisticsInfoSize
) {
371 *InfoSize
= StatisticsInfoSize
;
372 return EFI_BUFFER_TOO_SMALL
;
374 InfoName
= (CHAR16
*)(InfoEntry
+ 1);
376 CopyGuid (&VendorGuid
, &InfoEntry
->VendorGuid
);
378 if (CompareGuid (&VendorGuid
, &mZeroGuid
)) {
380 // Return the first variable info
382 CopyMem (InfoEntry
, VariableInfo
, sizeof (VARIABLE_INFO_ENTRY
));
383 CopyMem (InfoName
, VariableInfo
->Name
, StrSize (VariableInfo
->Name
));
384 *InfoSize
= StatisticsInfoSize
;
389 // Get the next variable info
391 while (VariableInfo
!= NULL
) {
392 if (CompareGuid (&VariableInfo
->VendorGuid
, &VendorGuid
)) {
393 NameLength
= StrSize (VariableInfo
->Name
);
394 if (NameLength
== StrSize (InfoName
)) {
395 if (CompareMem (VariableInfo
->Name
, InfoName
, NameLength
) == 0) {
397 // Find the match one
399 VariableInfo
= VariableInfo
->Next
;
404 VariableInfo
= VariableInfo
->Next
;
407 if (VariableInfo
== NULL
) {
413 // Output the new variable info
415 StatisticsInfoSize
= sizeof (VARIABLE_INFO_ENTRY
) + StrSize (VariableInfo
->Name
);
416 if (*InfoSize
< StatisticsInfoSize
) {
417 *InfoSize
= StatisticsInfoSize
;
418 return EFI_BUFFER_TOO_SMALL
;
421 CopyMem (InfoEntry
, VariableInfo
, sizeof (VARIABLE_INFO_ENTRY
));
422 CopyMem (InfoName
, VariableInfo
->Name
, StrSize (VariableInfo
->Name
));
423 *InfoSize
= StatisticsInfoSize
;
430 Communication service SMI Handler entry.
432 This SMI handler provides services for the variable wrapper driver.
434 Caution: This function may receive untrusted input.
435 This variable data and communicate buffer are external input, so this function will do basic validation.
436 Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
437 VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
438 SmmVariableGetStatistics() should also do validation based on its own knowledge.
440 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
441 @param[in] RegisterContext Points to an optional handler context which was specified when the
442 handler was registered.
443 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
444 be conveyed from a non-SMM environment into an SMM environment.
445 @param[in, out] CommBufferSize The size of the CommBuffer.
447 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
448 should still be called.
449 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
451 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
453 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
459 IN EFI_HANDLE DispatchHandle
,
460 IN CONST VOID
*RegisterContext
,
461 IN OUT VOID
*CommBuffer
,
462 IN OUT UINTN
*CommBufferSize
466 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
467 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
468 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*GetNextVariableName
;
469 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*QueryVariableInfo
;
470 VARIABLE_INFO_ENTRY
*VariableInfo
;
471 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
472 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
474 UINTN NameBufferSize
;
475 UINTN CommBufferPayloadSize
;
476 UINTN TempCommBufferSize
;
479 // If input is invalid, stop processing this SMI
481 if (CommBuffer
== NULL
|| CommBufferSize
== NULL
) {
485 TempCommBufferSize
= *CommBufferSize
;
487 if (TempCommBufferSize
< SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
488 DEBUG ((EFI_D_ERROR
, "SmmVariableHandler: SMM communication buffer size invalid!\n"));
491 CommBufferPayloadSize
= TempCommBufferSize
- SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
492 if (CommBufferPayloadSize
> mVariableBufferPayloadSize
) {
493 DEBUG ((EFI_D_ERROR
, "SmmVariableHandler: SMM communication buffer payload size invalid!\n"));
497 if (!SmmIsBufferOutsideSmmValid ((UINTN
)CommBuffer
, TempCommBufferSize
)) {
498 DEBUG ((EFI_D_ERROR
, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));
502 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)CommBuffer
;
504 switch (SmmVariableFunctionHeader
->Function
) {
505 case SMM_VARIABLE_FUNCTION_GET_VARIABLE
:
506 if (CommBufferPayloadSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
507 DEBUG ((EFI_D_ERROR
, "GetVariable: SMM communication buffer size invalid!\n"));
511 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
513 CopyMem (mVariableBufferPayload
, SmmVariableFunctionHeader
->Data
, CommBufferPayloadSize
);
514 SmmVariableHeader
= (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*) mVariableBufferPayload
;
515 if (((UINTN
)(~0) - SmmVariableHeader
->DataSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
516 ((UINTN
)(~0) - SmmVariableHeader
->NameSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + SmmVariableHeader
->DataSize
)) {
518 // Prevent InfoSize overflow happen
520 Status
= EFI_ACCESS_DENIED
;
523 InfoSize
= OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)
524 + SmmVariableHeader
->DataSize
+ SmmVariableHeader
->NameSize
;
527 // SMRAM range check already covered before
529 if (InfoSize
> CommBufferPayloadSize
) {
530 DEBUG ((EFI_D_ERROR
, "GetVariable: Data size exceed communication buffer size limit!\n"));
531 Status
= EFI_ACCESS_DENIED
;
535 if (SmmVariableHeader
->NameSize
< sizeof (CHAR16
) || SmmVariableHeader
->Name
[SmmVariableHeader
->NameSize
/sizeof (CHAR16
) - 1] != L
'\0') {
537 // Make sure VariableName is A Null-terminated string.
539 Status
= EFI_ACCESS_DENIED
;
543 Status
= VariableServiceGetVariable (
544 SmmVariableHeader
->Name
,
545 &SmmVariableHeader
->Guid
,
546 &SmmVariableHeader
->Attributes
,
547 &SmmVariableHeader
->DataSize
,
548 (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
550 CopyMem (SmmVariableFunctionHeader
->Data
, mVariableBufferPayload
, CommBufferPayloadSize
);
553 case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
:
554 if (CommBufferPayloadSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
555 DEBUG ((EFI_D_ERROR
, "GetNextVariableName: SMM communication buffer size invalid!\n"));
559 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
561 CopyMem (mVariableBufferPayload
, SmmVariableFunctionHeader
->Data
, CommBufferPayloadSize
);
562 GetNextVariableName
= (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*) mVariableBufferPayload
;
563 if ((UINTN
)(~0) - GetNextVariableName
->NameSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
565 // Prevent InfoSize overflow happen
567 Status
= EFI_ACCESS_DENIED
;
570 InfoSize
= OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + GetNextVariableName
->NameSize
;
573 // SMRAM range check already covered before
575 if (InfoSize
> CommBufferPayloadSize
) {
576 DEBUG ((EFI_D_ERROR
, "GetNextVariableName: Data size exceed communication buffer size limit!\n"));
577 Status
= EFI_ACCESS_DENIED
;
581 NameBufferSize
= CommBufferPayloadSize
- OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
582 if (NameBufferSize
< sizeof (CHAR16
) || GetNextVariableName
->Name
[NameBufferSize
/sizeof (CHAR16
) - 1] != L
'\0') {
584 // Make sure input VariableName is A Null-terminated string.
586 Status
= EFI_ACCESS_DENIED
;
590 Status
= VariableServiceGetNextVariableName (
591 &GetNextVariableName
->NameSize
,
592 GetNextVariableName
->Name
,
593 &GetNextVariableName
->Guid
595 CopyMem (SmmVariableFunctionHeader
->Data
, mVariableBufferPayload
, CommBufferPayloadSize
);
598 case SMM_VARIABLE_FUNCTION_SET_VARIABLE
:
599 if (CommBufferPayloadSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
600 DEBUG ((EFI_D_ERROR
, "SetVariable: SMM communication buffer size invalid!\n"));
604 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
606 CopyMem (mVariableBufferPayload
, SmmVariableFunctionHeader
->Data
, CommBufferPayloadSize
);
607 SmmVariableHeader
= (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*) mVariableBufferPayload
;
608 if (((UINTN
)(~0) - SmmVariableHeader
->DataSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
609 ((UINTN
)(~0) - SmmVariableHeader
->NameSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + SmmVariableHeader
->DataSize
)) {
611 // Prevent InfoSize overflow happen
613 Status
= EFI_ACCESS_DENIED
;
616 InfoSize
= OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)
617 + SmmVariableHeader
->DataSize
+ SmmVariableHeader
->NameSize
;
620 // SMRAM range check already covered before
621 // Data buffer should not contain SMM range
623 if (InfoSize
> CommBufferPayloadSize
) {
624 DEBUG ((EFI_D_ERROR
, "SetVariable: Data size exceed communication buffer size limit!\n"));
625 Status
= EFI_ACCESS_DENIED
;
629 if (SmmVariableHeader
->NameSize
< sizeof (CHAR16
) || SmmVariableHeader
->Name
[SmmVariableHeader
->NameSize
/sizeof (CHAR16
) - 1] != L
'\0') {
631 // Make sure VariableName is A Null-terminated string.
633 Status
= EFI_ACCESS_DENIED
;
637 Status
= VariableServiceSetVariable (
638 SmmVariableHeader
->Name
,
639 &SmmVariableHeader
->Guid
,
640 SmmVariableHeader
->Attributes
,
641 SmmVariableHeader
->DataSize
,
642 (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
646 case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
:
647 if (CommBufferPayloadSize
< sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
)) {
648 DEBUG ((EFI_D_ERROR
, "QueryVariableInfo: SMM communication buffer size invalid!\n"));
651 QueryVariableInfo
= (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*) SmmVariableFunctionHeader
->Data
;
653 Status
= VariableServiceQueryVariableInfo (
654 QueryVariableInfo
->Attributes
,
655 &QueryVariableInfo
->MaximumVariableStorageSize
,
656 &QueryVariableInfo
->RemainingVariableStorageSize
,
657 &QueryVariableInfo
->MaximumVariableSize
661 case SMM_VARIABLE_FUNCTION_READY_TO_BOOT
:
664 // The initialization for variable quota.
666 InitializeVariableQuota ();
668 Status
= EFI_UNSUPPORTED
;
672 Status
= EFI_SUCCESS
;
675 case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
:
677 Status
= EFI_SUCCESS
;
680 case SMM_VARIABLE_FUNCTION_GET_STATISTICS
:
681 VariableInfo
= (VARIABLE_INFO_ENTRY
*) SmmVariableFunctionHeader
->Data
;
682 InfoSize
= TempCommBufferSize
- SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
685 // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here.
686 // It is covered by previous CommBuffer check
689 if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS
)(UINTN
)CommBufferSize
, sizeof(UINTN
))) {
690 DEBUG ((EFI_D_ERROR
, "GetStatistics: SMM communication buffer in SMRAM!\n"));
691 Status
= EFI_ACCESS_DENIED
;
695 Status
= SmmVariableGetStatistics (VariableInfo
, &InfoSize
);
696 *CommBufferSize
= InfoSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
699 case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
:
701 Status
= EFI_ACCESS_DENIED
;
703 VariableToLock
= (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*) SmmVariableFunctionHeader
->Data
;
704 Status
= VariableLockRequestToLock (
706 VariableToLock
->Name
,
707 &VariableToLock
->Guid
711 case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
:
713 Status
= EFI_ACCESS_DENIED
;
715 CommVariableProperty
= (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*) SmmVariableFunctionHeader
->Data
;
716 Status
= VarCheckVariablePropertySet (
717 CommVariableProperty
->Name
,
718 &CommVariableProperty
->Guid
,
719 &CommVariableProperty
->VariableProperty
723 case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
:
724 if (CommBufferPayloadSize
< OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
725 DEBUG ((EFI_D_ERROR
, "VarCheckVariablePropertyGet: SMM communication buffer size invalid!\n"));
729 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
731 CopyMem (mVariableBufferPayload
, SmmVariableFunctionHeader
->Data
, CommBufferPayloadSize
);
732 CommVariableProperty
= (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*) mVariableBufferPayload
;
733 if ((UINTN
) (~0) - CommVariableProperty
->NameSize
< OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
735 // Prevent InfoSize overflow happen
737 Status
= EFI_ACCESS_DENIED
;
740 InfoSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + CommVariableProperty
->NameSize
;
743 // SMRAM range check already covered before
745 if (InfoSize
> CommBufferPayloadSize
) {
746 DEBUG ((EFI_D_ERROR
, "VarCheckVariablePropertyGet: Data size exceed communication buffer size limit!\n"));
747 Status
= EFI_ACCESS_DENIED
;
751 if (CommVariableProperty
->NameSize
< sizeof (CHAR16
) || CommVariableProperty
->Name
[CommVariableProperty
->NameSize
/sizeof (CHAR16
) - 1] != L
'\0') {
753 // Make sure VariableName is A Null-terminated string.
755 Status
= EFI_ACCESS_DENIED
;
759 Status
= VarCheckVariablePropertyGet (
760 CommVariableProperty
->Name
,
761 &CommVariableProperty
->Guid
,
762 &CommVariableProperty
->VariableProperty
764 CopyMem (SmmVariableFunctionHeader
->Data
, mVariableBufferPayload
, CommBufferPayloadSize
);
768 Status
= EFI_UNSUPPORTED
;
773 SmmVariableFunctionHeader
->ReturnStatus
= Status
;
778 SMM END_OF_DXE protocol notification event handler.
780 @param Protocol Points to the protocol's unique identifier
781 @param Interface Points to the interface instance
782 @param Handle The handle on which the interface was installed
784 @retval EFI_SUCCESS SmmEndOfDxeCallback runs successfully
789 SmmEndOfDxeCallback (
790 IN CONST EFI_GUID
*Protocol
,
795 DEBUG ((EFI_D_INFO
, "[Variable]END_OF_DXE is signaled\n"));
798 // The initialization for variable quota.
800 InitializeVariableQuota ();
801 if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe
)) {
808 SMM Fault Tolerant Write protocol notification event handler.
810 Non-Volatile variable write may needs FTW protocol to reclaim when
813 @param Protocol Points to the protocol's unique identifier
814 @param Interface Points to the interface instance
815 @param Handle The handle on which the interface was installed
817 @retval EFI_SUCCESS SmmEventCallback runs successfully
818 @retval EFI_NOT_FOUND The Fvb protocol for variable is not found.
823 SmmFtwNotificationEvent (
824 IN CONST EFI_GUID
*Protocol
,
830 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
831 EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL
*FtwProtocol
;
832 EFI_PHYSICAL_ADDRESS NvStorageVariableBase
;
833 UINTN FtwMaxBlockSize
;
835 if (mVariableModuleGlobal
->FvbInstance
!= NULL
) {
840 // Ensure SMM FTW protocol is installed.
842 Status
= GetFtwProtocol ((VOID
**)&FtwProtocol
);
843 if (EFI_ERROR (Status
)) {
847 Status
= FtwProtocol
->GetMaxBlockSize (FtwProtocol
, &FtwMaxBlockSize
);
848 if (!EFI_ERROR (Status
)) {
849 ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize
) <= FtwMaxBlockSize
);
853 // Find the proper FVB protocol for variable.
855 NvStorageVariableBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
856 if (NvStorageVariableBase
== 0) {
857 NvStorageVariableBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
859 Status
= GetFvbInfoByAddress (NvStorageVariableBase
, NULL
, &FvbProtocol
);
860 if (EFI_ERROR (Status
)) {
861 return EFI_NOT_FOUND
;
864 mVariableModuleGlobal
->FvbInstance
= FvbProtocol
;
866 Status
= VariableWriteServiceInitialize ();
867 if (EFI_ERROR (Status
)) {
868 DEBUG ((DEBUG_ERROR
, "Variable write service initialization failed. Status = %r\n", Status
));
872 // Notify the variable wrapper driver the variable write service is ready
874 Status
= gBS
->InstallProtocolInterface (
876 &gSmmVariableWriteGuid
,
877 EFI_NATIVE_INTERFACE
,
880 ASSERT_EFI_ERROR (Status
);
887 Variable Driver main entry point. The Variable driver places the 4 EFI
888 runtime services in the EFI System Table and installs arch protocols
889 for variable read and write services being available. It also registers
890 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
892 @param[in] ImageHandle The firmware allocated handle for the EFI image.
893 @param[in] SystemTable A pointer to the EFI System Table.
895 @retval EFI_SUCCESS Variable service successfully initialized.
900 VariableServiceInitialize (
901 IN EFI_HANDLE ImageHandle
,
902 IN EFI_SYSTEM_TABLE
*SystemTable
906 EFI_HANDLE VariableHandle
;
907 VOID
*SmmFtwRegistration
;
908 VOID
*SmmEndOfDxeRegistration
;
911 // Variable initialize.
913 Status
= VariableCommonInitialize ();
914 ASSERT_EFI_ERROR (Status
);
917 // Install the Smm Variable Protocol on a new handle.
919 VariableHandle
= NULL
;
920 Status
= gSmst
->SmmInstallProtocolInterface (
922 &gEfiSmmVariableProtocolGuid
,
923 EFI_NATIVE_INTERFACE
,
926 ASSERT_EFI_ERROR (Status
);
928 Status
= gSmst
->SmmInstallProtocolInterface (
930 &gEdkiiSmmVarCheckProtocolGuid
,
931 EFI_NATIVE_INTERFACE
,
934 ASSERT_EFI_ERROR (Status
);
936 mVariableBufferPayloadSize
= MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
)) +
937 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) - sizeof (VARIABLE_HEADER
);
939 Status
= gSmst
->SmmAllocatePool (
940 EfiRuntimeServicesData
,
941 mVariableBufferPayloadSize
,
942 (VOID
**)&mVariableBufferPayload
944 ASSERT_EFI_ERROR (Status
);
947 /// Register SMM variable SMI handler
949 VariableHandle
= NULL
;
950 Status
= gSmst
->SmiHandlerRegister (SmmVariableHandler
, &gEfiSmmVariableProtocolGuid
, &VariableHandle
);
951 ASSERT_EFI_ERROR (Status
);
954 // Notify the variable wrapper driver the variable service is ready
956 Status
= SystemTable
->BootServices
->InstallProtocolInterface (
958 &gEfiSmmVariableProtocolGuid
,
959 EFI_NATIVE_INTERFACE
,
962 ASSERT_EFI_ERROR (Status
);
965 // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.
967 Status
= gSmst
->SmmRegisterProtocolNotify (
968 &gEfiSmmEndOfDxeProtocolGuid
,
970 &SmmEndOfDxeRegistration
972 ASSERT_EFI_ERROR (Status
);
975 // Register FtwNotificationEvent () notify function.
977 Status
= gSmst
->SmmRegisterProtocolNotify (
978 &gEfiSmmFaultTolerantWriteProtocolGuid
,
979 SmmFtwNotificationEvent
,
982 ASSERT_EFI_ERROR (Status
);
984 SmmFtwNotificationEvent (NULL
, NULL
, NULL
);