3 The sample implementation for SMM variable protocol. And this driver
4 implements an SMI handler to communicate with the DXE runtime driver
5 to provide variable services.
7 Caution: This module requires additional review when modified.
8 This driver will have external input - variable data and communicate buffer in SMM mode.
9 This external input must be validated carefully to avoid security issue like
10 buffer overflow, integer overflow.
12 SmmVariableHandler() will receive untrusted input and do basic validation.
14 Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
15 VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
16 SmmVariableGetStatistics() should also do validation based on its own knowledge.
18 Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>
19 This program and the accompanying materials
20 are licensed and made available under the terms and conditions of the BSD License
21 which accompanies this distribution. The full text of the license may be found at
22 http://opensource.org/licenses/bsd-license.php
24 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
25 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>
33 #include <Library/SmmServicesTableLib.h>
35 #include <Guid/VariableFormat.h>
36 #include <Guid/SmmVariableCommon.h>
39 EFI_SMRAM_DESCRIPTOR
*mSmramRanges
;
40 UINTN mSmramRangeCount
;
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
;
50 EFI_SMM_VARIABLE_PROTOCOL gSmmVariable
= {
51 VariableServiceGetVariable
,
52 VariableServiceGetNextVariableName
,
53 VariableServiceSetVariable
,
54 VariableServiceQueryVariableInfo
59 Return TRUE if ExitBootServices () has been called.
61 @retval TRUE If ExitBootServices () has been called.
72 This function check if the address is in SMRAM.
74 @param Buffer the buffer address to be checked.
75 @param Length the buffer length to be checked.
77 @retval TRUE this address is in SMRAM.
78 @retval FALSE this address is NOT in SMRAM.
81 InternalIsAddressInSmram (
82 IN EFI_PHYSICAL_ADDRESS Buffer
,
88 for (Index
= 0; Index
< mSmramRangeCount
; Index
++) {
89 if (((Buffer
>= mSmramRanges
[Index
].CpuStart
) && (Buffer
< mSmramRanges
[Index
].CpuStart
+ mSmramRanges
[Index
].PhysicalSize
)) ||
90 ((mSmramRanges
[Index
].CpuStart
>= Buffer
) && (mSmramRanges
[Index
].CpuStart
< Buffer
+ Length
))) {
99 This function check if the address refered by Buffer and Length is valid.
101 @param Buffer the buffer address to be checked.
102 @param Length the buffer length to be checked.
104 @retval TRUE this address is valid.
105 @retval FALSE this address is NOT valid.
108 InternalIsAddressValid (
113 if (Buffer
> (MAX_ADDRESS
- Length
)) {
119 if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS
)Buffer
, (UINT64
)Length
)) {
126 Initializes a basic mutual exclusion lock.
128 This function initializes a basic mutual exclusion lock to the released state
129 and returns the lock. Each lock provides mutual exclusion access at its task
130 priority level. Since there is no preemption or multiprocessor support in EFI,
131 acquiring the lock only consists of raising to the locks TPL.
132 If Lock is NULL, then ASSERT().
133 If Priority is not a valid TPL value, then ASSERT().
135 @param Lock A pointer to the lock data structure to initialize.
136 @param Priority EFI TPL is associated with the lock.
143 IN OUT EFI_LOCK
*Lock
,
151 Acquires lock only at boot time. Simply returns at runtime.
153 This is a temperary function that will be removed when
154 EfiAcquireLock() in UefiLib can handle the call in UEFI
155 Runtimer driver in RT phase.
156 It calls EfiAcquireLock() at boot time, and simply returns
159 @param Lock A pointer to the lock to acquire.
163 AcquireLockOnlyAtBootTime (
172 Releases lock only at boot time. Simply returns at runtime.
174 This is a temperary function which will be removed when
175 EfiReleaseLock() in UefiLib can handle the call in UEFI
176 Runtimer driver in RT phase.
177 It calls EfiReleaseLock() at boot time and simply returns
180 @param Lock A pointer to the lock to release.
184 ReleaseLockOnlyAtBootTime (
192 Retrive the SMM Fault Tolerent Write protocol interface.
194 @param[out] FtwProtocol The interface of SMM Ftw protocol
196 @retval EFI_SUCCESS The SMM FTW protocol instance was found and returned in FtwProtocol.
197 @retval EFI_NOT_FOUND The SMM FTW protocol instance was not found.
198 @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
203 OUT VOID
**FtwProtocol
209 // Locate Smm Fault Tolerent Write protocol
211 Status
= gSmst
->SmmLocateProtocol (
212 &gEfiSmmFaultTolerantWriteProtocolGuid
,
221 Retrive the SMM FVB protocol interface by HANDLE.
223 @param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for
224 reading, writing, and erasing the target block.
225 @param[out] FvBlock The interface of SMM FVB protocol
227 @retval EFI_SUCCESS The interface information for the specified protocol was returned.
228 @retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol.
229 @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
234 IN EFI_HANDLE FvBlockHandle
,
235 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvBlock
239 // To get the SMM FVB protocol interface on the handle
241 return gSmst
->SmmHandleProtocol (
243 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
250 Function returns an array of handles that support the SMM FVB protocol
251 in a buffer allocated from pool.
253 @param[out] NumberHandles The number of handles returned in Buffer.
254 @param[out] Buffer A pointer to the buffer to return the requested
255 array of handles that support SMM FVB protocol.
257 @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
258 handles in Buffer was returned in NumberHandles.
259 @retval EFI_NOT_FOUND No SMM FVB handle was found.
260 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
261 @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
265 GetFvbCountAndBuffer (
266 OUT UINTN
*NumberHandles
,
267 OUT EFI_HANDLE
**Buffer
273 if ((NumberHandles
== NULL
) || (Buffer
== NULL
)) {
274 return EFI_INVALID_PARAMETER
;
280 Status
= gSmst
->SmmLocateHandle (
282 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
287 if (EFI_ERROR(Status
) && Status
!= EFI_BUFFER_TOO_SMALL
) {
288 return EFI_NOT_FOUND
;
291 *Buffer
= AllocatePool (BufferSize
);
292 if (*Buffer
== NULL
) {
293 return EFI_OUT_OF_RESOURCES
;
296 Status
= gSmst
->SmmLocateHandle (
298 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
304 *NumberHandles
= BufferSize
/ sizeof(EFI_HANDLE
);
305 if (EFI_ERROR(Status
)) {
316 Get the variable statistics information from the information buffer pointed by gVariableInfo.
318 Caution: This function may be invoked at SMM runtime.
319 InfoEntry and InfoSize are external input. Care must be taken to make sure not security issue at runtime.
321 @param[in, out] InfoEntry A pointer to the buffer of variable information entry.
322 On input, point to the variable information returned last time. if
323 InfoEntry->VendorGuid is zero, return the first information.
324 On output, point to the next variable information.
325 @param[in, out] InfoSize On input, the size of the variable information buffer.
326 On output, the returned variable information size.
328 @retval EFI_SUCCESS The variable information is found and returned successfully.
329 @retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The
330 PcdVariableCollectStatistics should be set TRUE to support it.
331 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information.
335 SmmVariableGetStatistics (
336 IN OUT VARIABLE_INFO_ENTRY
*InfoEntry
,
337 IN OUT UINTN
*InfoSize
340 VARIABLE_INFO_ENTRY
*VariableInfo
;
342 UINTN StatisticsInfoSize
;
346 ASSERT (InfoEntry
!= NULL
);
347 VariableInfo
= gVariableInfo
;
348 if (VariableInfo
== NULL
) {
349 return EFI_UNSUPPORTED
;
352 StatisticsInfoSize
= sizeof (VARIABLE_INFO_ENTRY
) + StrSize (VariableInfo
->Name
);
353 if (*InfoSize
< StatisticsInfoSize
) {
354 *InfoSize
= StatisticsInfoSize
;
355 return EFI_BUFFER_TOO_SMALL
;
357 InfoName
= (CHAR16
*)(InfoEntry
+ 1);
359 CopyGuid (&VendorGuid
, &InfoEntry
->VendorGuid
);
361 if (CompareGuid (&VendorGuid
, &mZeroGuid
)) {
363 // Return the first variable info
365 CopyMem (InfoEntry
, VariableInfo
, sizeof (VARIABLE_INFO_ENTRY
));
366 CopyMem (InfoName
, VariableInfo
->Name
, StrSize (VariableInfo
->Name
));
367 *InfoSize
= StatisticsInfoSize
;
372 // Get the next variable info
374 while (VariableInfo
!= NULL
) {
375 if (CompareGuid (&VariableInfo
->VendorGuid
, &VendorGuid
)) {
376 NameLength
= StrSize (VariableInfo
->Name
);
377 if (NameLength
== StrSize (InfoName
)) {
378 if (CompareMem (VariableInfo
->Name
, InfoName
, NameLength
) == 0) {
380 // Find the match one
382 VariableInfo
= VariableInfo
->Next
;
387 VariableInfo
= VariableInfo
->Next
;
390 if (VariableInfo
== NULL
) {
396 // Output the new variable info
398 StatisticsInfoSize
= sizeof (VARIABLE_INFO_ENTRY
) + StrSize (VariableInfo
->Name
);
399 if (*InfoSize
< StatisticsInfoSize
) {
400 *InfoSize
= StatisticsInfoSize
;
401 return EFI_BUFFER_TOO_SMALL
;
404 CopyMem (InfoEntry
, VariableInfo
, sizeof (VARIABLE_INFO_ENTRY
));
405 CopyMem (InfoName
, VariableInfo
->Name
, StrSize (VariableInfo
->Name
));
406 *InfoSize
= StatisticsInfoSize
;
413 Communication service SMI Handler entry.
415 This SMI handler provides services for the variable wrapper driver.
417 Caution: This function may receive untrusted input.
418 This variable data and communicate buffer are external input, so this function will do basic validation.
419 Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
420 VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
421 SmmVariableGetStatistics() should also do validation based on its own knowledge.
423 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
424 @param[in] RegisterContext Points to an optional handler context which was specified when the
425 handler was registered.
426 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
427 be conveyed from a non-SMM environment into an SMM environment.
428 @param[in, out] CommBufferSize The size of the CommBuffer.
430 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
431 should still be called.
432 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
434 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
436 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
441 IN EFI_HANDLE DispatchHandle
,
442 IN CONST VOID
*RegisterContext
,
443 IN OUT VOID
*CommBuffer
,
444 IN OUT UINTN
*CommBufferSize
448 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
449 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
450 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*GetNextVariableName
;
451 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*QueryVariableInfo
;
452 VARIABLE_INFO_ENTRY
*VariableInfo
;
454 UINTN NameBufferSize
;
455 UINTN CommBufferPayloadSize
;
458 // If input is invalid, stop processing this SMI
460 if (CommBuffer
== NULL
|| CommBufferSize
== NULL
) {
464 if (*CommBufferSize
< SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
465 DEBUG ((EFI_D_ERROR
, "SmmVariableHandler: SMM communication buffer size invalid!\n"));
468 CommBufferPayloadSize
= *CommBufferSize
- SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
469 if (CommBufferPayloadSize
> mVariableBufferPayloadSize
) {
470 DEBUG ((EFI_D_ERROR
, "SmmVariableHandler: SMM communication buffer payload size invalid!\n"));
474 if (!InternalIsAddressValid ((UINTN
)CommBuffer
, *CommBufferSize
)) {
475 DEBUG ((EFI_D_ERROR
, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));
479 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)CommBuffer
;
480 switch (SmmVariableFunctionHeader
->Function
) {
481 case SMM_VARIABLE_FUNCTION_GET_VARIABLE
:
482 if (CommBufferPayloadSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
483 DEBUG ((EFI_D_ERROR
, "GetVariable: SMM communication buffer size invalid!\n"));
487 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
489 CopyMem (mVariableBufferPayload
, SmmVariableFunctionHeader
->Data
, CommBufferPayloadSize
);
490 SmmVariableHeader
= (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*) mVariableBufferPayload
;
491 if (((UINTN
)(~0) - SmmVariableHeader
->DataSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
492 ((UINTN
)(~0) - SmmVariableHeader
->NameSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + SmmVariableHeader
->DataSize
)) {
494 // Prevent InfoSize overflow happen
496 Status
= EFI_ACCESS_DENIED
;
499 InfoSize
= OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)
500 + SmmVariableHeader
->DataSize
+ SmmVariableHeader
->NameSize
;
503 // SMRAM range check already covered before
505 if (InfoSize
> CommBufferPayloadSize
) {
506 DEBUG ((EFI_D_ERROR
, "GetVariable: Data size exceed communication buffer size limit!\n"));
507 Status
= EFI_ACCESS_DENIED
;
511 if (SmmVariableHeader
->NameSize
< sizeof (CHAR16
) || SmmVariableHeader
->Name
[SmmVariableHeader
->NameSize
/sizeof (CHAR16
) - 1] != L
'\0') {
513 // Make sure VariableName is A Null-terminated string.
515 Status
= EFI_ACCESS_DENIED
;
519 Status
= VariableServiceGetVariable (
520 SmmVariableHeader
->Name
,
521 &SmmVariableHeader
->Guid
,
522 &SmmVariableHeader
->Attributes
,
523 &SmmVariableHeader
->DataSize
,
524 (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
526 CopyMem (SmmVariableFunctionHeader
->Data
, mVariableBufferPayload
, CommBufferPayloadSize
);
529 case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
:
530 if (CommBufferPayloadSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
531 DEBUG ((EFI_D_ERROR
, "GetNextVariableName: SMM communication buffer size invalid!\n"));
535 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
537 CopyMem (mVariableBufferPayload
, SmmVariableFunctionHeader
->Data
, CommBufferPayloadSize
);
538 GetNextVariableName
= (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*) mVariableBufferPayload
;
539 if ((UINTN
)(~0) - GetNextVariableName
->NameSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
541 // Prevent InfoSize overflow happen
543 Status
= EFI_ACCESS_DENIED
;
546 InfoSize
= OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + GetNextVariableName
->NameSize
;
549 // SMRAM range check already covered before
551 if (InfoSize
> CommBufferPayloadSize
) {
552 DEBUG ((EFI_D_ERROR
, "GetNextVariableName: Data size exceed communication buffer size limit!\n"));
553 Status
= EFI_ACCESS_DENIED
;
557 NameBufferSize
= CommBufferPayloadSize
- OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
558 if (NameBufferSize
< sizeof (CHAR16
) || GetNextVariableName
->Name
[NameBufferSize
/sizeof (CHAR16
) - 1] != L
'\0') {
560 // Make sure input VariableName is A Null-terminated string.
562 Status
= EFI_ACCESS_DENIED
;
566 Status
= VariableServiceGetNextVariableName (
567 &GetNextVariableName
->NameSize
,
568 GetNextVariableName
->Name
,
569 &GetNextVariableName
->Guid
571 CopyMem (SmmVariableFunctionHeader
->Data
, mVariableBufferPayload
, CommBufferPayloadSize
);
574 case SMM_VARIABLE_FUNCTION_SET_VARIABLE
:
575 if (CommBufferPayloadSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
576 DEBUG ((EFI_D_ERROR
, "SetVariable: SMM communication buffer size invalid!\n"));
580 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.
582 CopyMem (mVariableBufferPayload
, SmmVariableFunctionHeader
->Data
, CommBufferPayloadSize
);
583 SmmVariableHeader
= (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*) mVariableBufferPayload
;
584 if (((UINTN
)(~0) - SmmVariableHeader
->DataSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
585 ((UINTN
)(~0) - SmmVariableHeader
->NameSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + SmmVariableHeader
->DataSize
)) {
587 // Prevent InfoSize overflow happen
589 Status
= EFI_ACCESS_DENIED
;
592 InfoSize
= OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)
593 + SmmVariableHeader
->DataSize
+ SmmVariableHeader
->NameSize
;
596 // SMRAM range check already covered before
597 // Data buffer should not contain SMM range
599 if (InfoSize
> CommBufferPayloadSize
) {
600 DEBUG ((EFI_D_ERROR
, "SetVariable: Data size exceed communication buffer size limit!\n"));
601 Status
= EFI_ACCESS_DENIED
;
605 if (SmmVariableHeader
->NameSize
< sizeof (CHAR16
) || SmmVariableHeader
->Name
[SmmVariableHeader
->NameSize
/sizeof (CHAR16
) - 1] != L
'\0') {
607 // Make sure VariableName is A Null-terminated string.
609 Status
= EFI_ACCESS_DENIED
;
613 Status
= VariableServiceSetVariable (
614 SmmVariableHeader
->Name
,
615 &SmmVariableHeader
->Guid
,
616 SmmVariableHeader
->Attributes
,
617 SmmVariableHeader
->DataSize
,
618 (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
622 case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
:
623 if (CommBufferPayloadSize
< sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
)) {
624 DEBUG ((EFI_D_ERROR
, "QueryVariableInfo: SMM communication buffer size invalid!\n"));
627 QueryVariableInfo
= (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*) SmmVariableFunctionHeader
->Data
;
629 Status
= VariableServiceQueryVariableInfo (
630 QueryVariableInfo
->Attributes
,
631 &QueryVariableInfo
->MaximumVariableStorageSize
,
632 &QueryVariableInfo
->RemainingVariableStorageSize
,
633 &QueryVariableInfo
->MaximumVariableSize
637 case SMM_VARIABLE_FUNCTION_READY_TO_BOOT
:
639 Status
= EFI_UNSUPPORTED
;
643 Status
= EFI_SUCCESS
;
646 case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
:
648 Status
= EFI_SUCCESS
;
651 case SMM_VARIABLE_FUNCTION_GET_STATISTICS
:
652 VariableInfo
= (VARIABLE_INFO_ENTRY
*) SmmVariableFunctionHeader
->Data
;
653 InfoSize
= *CommBufferSize
- SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
656 // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here.
657 // It is covered by previous CommBuffer check
660 if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS
)(UINTN
)CommBufferSize
, sizeof(UINTN
))) {
661 DEBUG ((EFI_D_ERROR
, "GetStatistics: SMM communication buffer in SMRAM!\n"));
662 Status
= EFI_ACCESS_DENIED
;
666 Status
= SmmVariableGetStatistics (VariableInfo
, &InfoSize
);
667 *CommBufferSize
= InfoSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
671 Status
= EFI_UNSUPPORTED
;
676 SmmVariableFunctionHeader
->ReturnStatus
= Status
;
683 SMM Fault Tolerant Write protocol notification event handler.
685 Non-Volatile variable write may needs FTW protocol to reclaim when
688 @param Protocol Points to the protocol's unique identifier
689 @param Interface Points to the interface instance
690 @param Handle The handle on which the interface was installed
692 @retval EFI_SUCCESS SmmEventCallback runs successfully
693 @retval EFI_NOT_FOUND The Fvb protocol for variable is not found.
698 SmmFtwNotificationEvent (
699 IN CONST EFI_GUID
*Protocol
,
705 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
706 EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL
*FtwProtocol
;
707 EFI_PHYSICAL_ADDRESS NvStorageVariableBase
;
709 if (mVariableModuleGlobal
->FvbInstance
!= NULL
) {
714 // Ensure SMM FTW protocol is installed.
716 Status
= GetFtwProtocol ((VOID
**)&FtwProtocol
);
717 if (EFI_ERROR (Status
)) {
722 // Find the proper FVB protocol for variable.
724 NvStorageVariableBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
725 if (NvStorageVariableBase
== 0) {
726 NvStorageVariableBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
728 Status
= GetFvbInfoByAddress (NvStorageVariableBase
, NULL
, &FvbProtocol
);
729 if (EFI_ERROR (Status
)) {
730 return EFI_NOT_FOUND
;
733 mVariableModuleGlobal
->FvbInstance
= FvbProtocol
;
735 Status
= VariableWriteServiceInitialize ();
736 ASSERT_EFI_ERROR (Status
);
739 // Notify the variable wrapper driver the variable write service is ready
741 Status
= gBS
->InstallProtocolInterface (
743 &gSmmVariableWriteGuid
,
744 EFI_NATIVE_INTERFACE
,
747 ASSERT_EFI_ERROR (Status
);
754 Variable Driver main entry point. The Variable driver places the 4 EFI
755 runtime services in the EFI System Table and installs arch protocols
756 for variable read and write services being available. It also registers
757 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
759 @param[in] ImageHandle The firmware allocated handle for the EFI image.
760 @param[in] SystemTable A pointer to the EFI System Table.
762 @retval EFI_SUCCESS Variable service successfully initialized.
767 VariableServiceInitialize (
768 IN EFI_HANDLE ImageHandle
,
769 IN EFI_SYSTEM_TABLE
*SystemTable
773 EFI_HANDLE VariableHandle
;
774 VOID
*SmmFtwRegistration
;
775 EFI_SMM_ACCESS2_PROTOCOL
*SmmAccess
;
779 // Variable initialize.
781 Status
= VariableCommonInitialize ();
782 ASSERT_EFI_ERROR (Status
);
785 // Install the Smm Variable Protocol on a new handle.
787 VariableHandle
= NULL
;
788 Status
= gSmst
->SmmInstallProtocolInterface (
790 &gEfiSmmVariableProtocolGuid
,
791 EFI_NATIVE_INTERFACE
,
794 ASSERT_EFI_ERROR (Status
);
797 // Get SMRAM information
799 Status
= gBS
->LocateProtocol (&gEfiSmmAccess2ProtocolGuid
, NULL
, (VOID
**)&SmmAccess
);
800 ASSERT_EFI_ERROR (Status
);
803 Status
= SmmAccess
->GetCapabilities (SmmAccess
, &Size
, NULL
);
804 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
806 Status
= gSmst
->SmmAllocatePool (
807 EfiRuntimeServicesData
,
809 (VOID
**)&mSmramRanges
811 ASSERT_EFI_ERROR (Status
);
813 Status
= SmmAccess
->GetCapabilities (SmmAccess
, &Size
, mSmramRanges
);
814 ASSERT_EFI_ERROR (Status
);
816 mSmramRangeCount
= Size
/ sizeof (EFI_SMRAM_DESCRIPTOR
);
818 mVariableBufferPayloadSize
= MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
)) +
819 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - sizeof (VARIABLE_HEADER
);
821 Status
= gSmst
->SmmAllocatePool (
822 EfiRuntimeServicesData
,
823 mVariableBufferPayloadSize
,
824 (VOID
**)&mVariableBufferPayload
826 ASSERT_EFI_ERROR (Status
);
829 /// Register SMM variable SMI handler
831 VariableHandle
= NULL
;
832 Status
= gSmst
->SmiHandlerRegister (SmmVariableHandler
, &gEfiSmmVariableProtocolGuid
, &VariableHandle
);
833 ASSERT_EFI_ERROR (Status
);
836 // Notify the variable wrapper driver the variable service is ready
838 Status
= SystemTable
->BootServices
->InstallProtocolInterface (
840 &gEfiSmmVariableProtocolGuid
,
841 EFI_NATIVE_INTERFACE
,
844 ASSERT_EFI_ERROR (Status
);
847 // Register FtwNotificationEvent () notify function.
849 Status
= gSmst
->SmmRegisterProtocolNotify (
850 &gEfiSmmFaultTolerantWriteProtocolGuid
,
851 SmmFtwNotificationEvent
,
854 ASSERT_EFI_ERROR (Status
);
856 SmmFtwNotificationEvent (NULL
, NULL
, NULL
);