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 - 2012, 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>
33 #include <Library/SmmServicesTableLib.h>
35 #include <Guid/AuthenticatedVariableFormat.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}};
48 EFI_SMM_VARIABLE_PROTOCOL gSmmVariable
= {
49 VariableServiceGetVariable
,
50 VariableServiceGetNextVariableName
,
51 VariableServiceSetVariable
,
52 VariableServiceQueryVariableInfo
57 Return TRUE if ExitBootServices () has been called.
59 @retval TRUE If ExitBootServices () has been called.
70 This function check if the address is in SMRAM.
72 @param Buffer the buffer address to be checked.
73 @param Length the buffer length to be checked.
75 @retval TRUE this address is in SMRAM.
76 @retval FALSE this address is NOT in SMRAM.
79 InternalIsAddressInSmram (
80 IN EFI_PHYSICAL_ADDRESS Buffer
,
86 for (Index
= 0; Index
< mSmramRangeCount
; Index
++) {
87 if (((Buffer
>= mSmramRanges
[Index
].CpuStart
) && (Buffer
< mSmramRanges
[Index
].CpuStart
+ mSmramRanges
[Index
].PhysicalSize
)) ||
88 ((mSmramRanges
[Index
].CpuStart
>= Buffer
) && (mSmramRanges
[Index
].CpuStart
< Buffer
+ Length
))) {
97 This function check if the address refered by Buffer and Length is valid.
99 @param Buffer the buffer address to be checked.
100 @param Length the buffer length to be checked.
102 @retval TRUE this address is valid.
103 @retval FALSE this address is NOT valid.
106 InternalIsAddressValid (
111 if (Buffer
> (MAX_ADDRESS
- Length
)) {
117 if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS
)Buffer
, (UINT64
)Length
)) {
124 Initializes a basic mutual exclusion lock.
126 This function initializes a basic mutual exclusion lock to the released state
127 and returns the lock. Each lock provides mutual exclusion access at its task
128 priority level. Since there is no preemption or multiprocessor support in EFI,
129 acquiring the lock only consists of raising to the locks TPL.
130 If Lock is NULL, then ASSERT().
131 If Priority is not a valid TPL value, then ASSERT().
133 @param Lock A pointer to the lock data structure to initialize.
134 @param Priority EFI TPL is associated with the lock.
141 IN OUT EFI_LOCK
*Lock
,
149 Acquires lock only at boot time. Simply returns at runtime.
151 This is a temperary function that will be removed when
152 EfiAcquireLock() in UefiLib can handle the call in UEFI
153 Runtimer driver in RT phase.
154 It calls EfiAcquireLock() at boot time, and simply returns
157 @param Lock A pointer to the lock to acquire.
161 AcquireLockOnlyAtBootTime (
170 Releases lock only at boot time. Simply returns at runtime.
172 This is a temperary function which will be removed when
173 EfiReleaseLock() in UefiLib can handle the call in UEFI
174 Runtimer driver in RT phase.
175 It calls EfiReleaseLock() at boot time and simply returns
178 @param Lock A pointer to the lock to release.
182 ReleaseLockOnlyAtBootTime (
190 Retrive the SMM Fault Tolerent Write protocol interface.
192 @param[out] FtwProtocol The interface of SMM Ftw protocol
194 @retval EFI_SUCCESS The SMM FTW protocol instance was found and returned in FtwProtocol.
195 @retval EFI_NOT_FOUND The SMM FTW protocol instance was not found.
196 @retval EFI_INVALID_PARAMETER SarProtocol is NULL.
201 OUT VOID
**FtwProtocol
207 // Locate Smm Fault Tolerent Write protocol
209 Status
= gSmst
->SmmLocateProtocol (
210 &gEfiSmmFaultTolerantWriteProtocolGuid
,
219 Retrive the SMM FVB protocol interface by HANDLE.
221 @param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for
222 reading, writing, and erasing the target block.
223 @param[out] FvBlock The interface of SMM FVB protocol
225 @retval EFI_SUCCESS The interface information for the specified protocol was returned.
226 @retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol.
227 @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.
232 IN EFI_HANDLE FvBlockHandle
,
233 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
**FvBlock
237 // To get the SMM FVB protocol interface on the handle
239 return gSmst
->SmmHandleProtocol (
241 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
248 Function returns an array of handles that support the SMM FVB protocol
249 in a buffer allocated from pool.
251 @param[out] NumberHandles The number of handles returned in Buffer.
252 @param[out] Buffer A pointer to the buffer to return the requested
253 array of handles that support SMM FVB protocol.
255 @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of
256 handles in Buffer was returned in NumberHandles.
257 @retval EFI_NOT_FOUND No SMM FVB handle was found.
258 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.
259 @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.
263 GetFvbCountAndBuffer (
264 OUT UINTN
*NumberHandles
,
265 OUT EFI_HANDLE
**Buffer
271 if ((NumberHandles
== NULL
) || (Buffer
== NULL
)) {
272 return EFI_INVALID_PARAMETER
;
278 Status
= gSmst
->SmmLocateHandle (
280 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
285 if (EFI_ERROR(Status
) && Status
!= EFI_BUFFER_TOO_SMALL
) {
286 return EFI_NOT_FOUND
;
289 *Buffer
= AllocatePool (BufferSize
);
290 if (*Buffer
== NULL
) {
291 return EFI_OUT_OF_RESOURCES
;
294 Status
= gSmst
->SmmLocateHandle (
296 &gEfiSmmFirmwareVolumeBlockProtocolGuid
,
302 *NumberHandles
= BufferSize
/ sizeof(EFI_HANDLE
);
303 if (EFI_ERROR(Status
)) {
312 Get the variable statistics information from the information buffer pointed by gVariableInfo.
314 Caution: This function may be invoked at SMM runtime.
315 InfoEntry and InfoSize are external input. Care must be taken to make sure not security issue at runtime.
317 @param[in, out] InfoEntry A pointer to the buffer of variable information entry.
318 On input, point to the variable information returned last time. if
319 InfoEntry->VendorGuid is zero, return the first information.
320 On output, point to the next variable information.
321 @param[in, out] InfoSize On input, the size of the variable information buffer.
322 On output, the returned variable information size.
324 @retval EFI_SUCCESS The variable information is found and returned successfully.
325 @retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The
326 PcdVariableCollectStatistics should be set TRUE to support it.
327 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information.
328 @retval EFI_INVALID_PARAMETER Input parameter is invalid.
332 SmmVariableGetStatistics (
333 IN OUT VARIABLE_INFO_ENTRY
*InfoEntry
,
334 IN OUT UINTN
*InfoSize
337 VARIABLE_INFO_ENTRY
*VariableInfo
;
339 UINTN StatisticsInfoSize
;
342 if (InfoEntry
== NULL
) {
343 return EFI_INVALID_PARAMETER
;
346 VariableInfo
= gVariableInfo
;
347 if (VariableInfo
== NULL
) {
348 return EFI_UNSUPPORTED
;
351 StatisticsInfoSize
= sizeof (VARIABLE_INFO_ENTRY
) + StrSize (VariableInfo
->Name
);
352 if (*InfoSize
< StatisticsInfoSize
) {
353 *InfoSize
= StatisticsInfoSize
;
354 return EFI_BUFFER_TOO_SMALL
;
356 InfoName
= (CHAR16
*)(InfoEntry
+ 1);
358 if (CompareGuid (&InfoEntry
->VendorGuid
, &mZeroGuid
)) {
360 // Return the first variable info
362 CopyMem (InfoEntry
, VariableInfo
, sizeof (VARIABLE_INFO_ENTRY
));
363 CopyMem (InfoName
, VariableInfo
->Name
, StrSize (VariableInfo
->Name
));
364 *InfoSize
= StatisticsInfoSize
;
369 // Get the next variable info
371 while (VariableInfo
!= NULL
) {
372 if (CompareGuid (&VariableInfo
->VendorGuid
, &InfoEntry
->VendorGuid
)) {
373 NameLength
= StrSize (VariableInfo
->Name
);
374 if (NameLength
== StrSize (InfoName
)) {
375 if (CompareMem (VariableInfo
->Name
, InfoName
, NameLength
) == 0) {
377 // Find the match one
379 VariableInfo
= VariableInfo
->Next
;
384 VariableInfo
= VariableInfo
->Next
;
387 if (VariableInfo
== NULL
) {
393 // Output the new variable info
395 StatisticsInfoSize
= sizeof (VARIABLE_INFO_ENTRY
) + StrSize (VariableInfo
->Name
);
396 if (*InfoSize
< StatisticsInfoSize
) {
397 *InfoSize
= StatisticsInfoSize
;
398 return EFI_BUFFER_TOO_SMALL
;
401 CopyMem (InfoEntry
, VariableInfo
, sizeof (VARIABLE_INFO_ENTRY
));
402 CopyMem (InfoName
, VariableInfo
->Name
, StrSize (VariableInfo
->Name
));
403 *InfoSize
= StatisticsInfoSize
;
410 Communication service SMI Handler entry.
412 This SMI handler provides services for the variable wrapper driver.
414 Caution: This function may receive untrusted input.
415 This variable data and communicate buffer are external input, so this function will do basic validation.
416 Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),
417 VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),
418 SmmVariableGetStatistics() should also do validation based on its own knowledge.
420 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
421 @param[in] RegisterContext Points to an optional handler context which was specified when the
422 handler was registered.
423 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
424 be conveyed from a non-SMM environment into an SMM environment.
425 @param[in, out] CommBufferSize The size of the CommBuffer.
427 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
428 should still be called.
429 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should
431 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still
433 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.
439 IN EFI_HANDLE DispatchHandle
,
440 IN CONST VOID
*RegisterContext
,
441 IN OUT VOID
*CommBuffer
,
442 IN OUT UINTN
*CommBufferSize
446 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
447 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
448 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*GetNextVariableName
;
449 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*QueryVariableInfo
;
450 VARIABLE_INFO_ENTRY
*VariableInfo
;
452 UINTN NameBufferSize
;
455 // If input is invalid, stop processing this SMI
457 if (CommBuffer
== NULL
|| CommBufferSize
== NULL
) {
461 if (*CommBufferSize
< SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
465 if (!InternalIsAddressValid ((UINTN
)CommBuffer
, *CommBufferSize
)) {
466 DEBUG ((EFI_D_ERROR
, "SMM communication buffer in SMRAM or overflow!\n"));
470 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)CommBuffer
;
472 switch (SmmVariableFunctionHeader
->Function
) {
473 case SMM_VARIABLE_FUNCTION_GET_VARIABLE
:
474 SmmVariableHeader
= (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*) SmmVariableFunctionHeader
->Data
;
475 if (((UINTN
)(~0) - SmmVariableHeader
->DataSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
476 ((UINTN
)(~0) - SmmVariableHeader
->NameSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + SmmVariableHeader
->DataSize
)) {
478 // Prevent InfoSize overflow happen
480 Status
= EFI_ACCESS_DENIED
;
483 InfoSize
= OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)
484 + SmmVariableHeader
->DataSize
+ SmmVariableHeader
->NameSize
;
487 // SMRAM range check already covered before
489 if (InfoSize
> *CommBufferSize
- SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
490 DEBUG ((EFI_D_ERROR
, "Data size exceed communication buffer size limit!\n"));
491 Status
= EFI_ACCESS_DENIED
;
495 if (SmmVariableHeader
->NameSize
< sizeof (CHAR16
) || SmmVariableHeader
->Name
[SmmVariableHeader
->NameSize
/sizeof (CHAR16
) - 1] != L
'\0') {
497 // Make sure VariableName is A Null-terminated string.
499 Status
= EFI_ACCESS_DENIED
;
503 Status
= VariableServiceGetVariable (
504 SmmVariableHeader
->Name
,
505 &SmmVariableHeader
->Guid
,
506 &SmmVariableHeader
->Attributes
,
507 &SmmVariableHeader
->DataSize
,
508 (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
512 case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
:
513 GetNextVariableName
= (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*) SmmVariableFunctionHeader
->Data
;
514 if ((UINTN
)(~0) - GetNextVariableName
->NameSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
516 // Prevent InfoSize overflow happen
518 Status
= EFI_ACCESS_DENIED
;
521 InfoSize
= OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + GetNextVariableName
->NameSize
;
524 // SMRAM range check already covered before
526 if (InfoSize
> *CommBufferSize
- SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
527 DEBUG ((EFI_D_ERROR
, "Data size exceed communication buffer size limit!\n"));
528 Status
= EFI_ACCESS_DENIED
;
532 NameBufferSize
= *CommBufferSize
- SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
- OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
533 if (NameBufferSize
< sizeof (CHAR16
) || GetNextVariableName
->Name
[NameBufferSize
/sizeof (CHAR16
) - 1] != L
'\0') {
535 // Make sure input VariableName is A Null-terminated string.
537 Status
= EFI_ACCESS_DENIED
;
541 Status
= VariableServiceGetNextVariableName (
542 &GetNextVariableName
->NameSize
,
543 GetNextVariableName
->Name
,
544 &GetNextVariableName
->Guid
548 case SMM_VARIABLE_FUNCTION_SET_VARIABLE
:
549 SmmVariableHeader
= (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*) SmmVariableFunctionHeader
->Data
;
550 if (((UINTN
)(~0) - SmmVariableHeader
->DataSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
551 ((UINTN
)(~0) - SmmVariableHeader
->NameSize
< OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + SmmVariableHeader
->DataSize
)) {
553 // Prevent InfoSize overflow happen
555 Status
= EFI_ACCESS_DENIED
;
558 InfoSize
= OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)
559 + SmmVariableHeader
->DataSize
+ SmmVariableHeader
->NameSize
;
562 // SMRAM range check already covered before
563 // Data buffer should not contain SMM range
565 if (InfoSize
> *CommBufferSize
- SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
566 DEBUG ((EFI_D_ERROR
, "Data size exceed communication buffer size limit!\n"));
567 Status
= EFI_ACCESS_DENIED
;
571 if (SmmVariableHeader
->NameSize
< sizeof (CHAR16
) || SmmVariableHeader
->Name
[SmmVariableHeader
->NameSize
/sizeof (CHAR16
) - 1] != L
'\0') {
573 // Make sure VariableName is A Null-terminated string.
575 Status
= EFI_ACCESS_DENIED
;
579 Status
= VariableServiceSetVariable (
580 SmmVariableHeader
->Name
,
581 &SmmVariableHeader
->Guid
,
582 SmmVariableHeader
->Attributes
,
583 SmmVariableHeader
->DataSize
,
584 (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
588 case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
:
589 QueryVariableInfo
= (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*) SmmVariableFunctionHeader
->Data
;
590 InfoSize
= sizeof(SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
593 // SMRAM range check already covered before
595 if (InfoSize
> *CommBufferSize
- SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
) {
596 DEBUG ((EFI_D_ERROR
, "Data size exceed communication buffer size limit!\n"));
597 Status
= EFI_ACCESS_DENIED
;
601 Status
= VariableServiceQueryVariableInfo (
602 QueryVariableInfo
->Attributes
,
603 &QueryVariableInfo
->MaximumVariableStorageSize
,
604 &QueryVariableInfo
->RemainingVariableStorageSize
,
605 &QueryVariableInfo
->MaximumVariableSize
609 case SMM_VARIABLE_FUNCTION_READY_TO_BOOT
:
611 Status
= EFI_UNSUPPORTED
;
615 Status
= EFI_SUCCESS
;
618 case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
:
620 Status
= EFI_SUCCESS
;
623 case SMM_VARIABLE_FUNCTION_GET_STATISTICS
:
624 VariableInfo
= (VARIABLE_INFO_ENTRY
*) SmmVariableFunctionHeader
->Data
;
625 InfoSize
= *CommBufferSize
- SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
628 // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here.
629 // It is covered by previous CommBuffer check
632 if (InternalIsAddressInSmram ((EFI_PHYSICAL_ADDRESS
)(UINTN
)CommBufferSize
, sizeof(UINTN
))) {
633 DEBUG ((EFI_D_ERROR
, "SMM communication buffer in SMRAM!\n"));
634 Status
= EFI_ACCESS_DENIED
;
638 Status
= SmmVariableGetStatistics (VariableInfo
, &InfoSize
);
639 *CommBufferSize
= InfoSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
643 Status
= EFI_UNSUPPORTED
;
648 SmmVariableFunctionHeader
->ReturnStatus
= Status
;
654 SMM Fault Tolerant Write protocol notification event handler.
656 Non-Volatile variable write may needs FTW protocol to reclaim when
659 @param Protocol Points to the protocol's unique identifier
660 @param Interface Points to the interface instance
661 @param Handle The handle on which the interface was installed
663 @retval EFI_SUCCESS SmmEventCallback runs successfully
664 @retval EFI_NOT_FOUND The Fvb protocol for variable is not found.
669 SmmFtwNotificationEvent (
670 IN CONST EFI_GUID
*Protocol
,
676 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*FvbProtocol
;
677 EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL
*FtwProtocol
;
678 EFI_PHYSICAL_ADDRESS NvStorageVariableBase
;
680 if (mVariableModuleGlobal
->FvbInstance
!= NULL
) {
685 // Ensure SMM FTW protocol is installed.
687 Status
= GetFtwProtocol ((VOID
**)&FtwProtocol
);
688 if (EFI_ERROR (Status
)) {
693 // Find the proper FVB protocol for variable.
695 NvStorageVariableBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet64 (PcdFlashNvStorageVariableBase64
);
696 if (NvStorageVariableBase
== 0) {
697 NvStorageVariableBase
= (EFI_PHYSICAL_ADDRESS
) PcdGet32 (PcdFlashNvStorageVariableBase
);
699 Status
= GetFvbInfoByAddress (NvStorageVariableBase
, NULL
, &FvbProtocol
);
700 if (EFI_ERROR (Status
)) {
701 return EFI_NOT_FOUND
;
704 mVariableModuleGlobal
->FvbInstance
= FvbProtocol
;
706 Status
= VariableWriteServiceInitialize ();
707 ASSERT_EFI_ERROR (Status
);
710 // Notify the variable wrapper driver the variable write service is ready
712 Status
= gBS
->InstallProtocolInterface (
714 &gSmmVariableWriteGuid
,
715 EFI_NATIVE_INTERFACE
,
718 ASSERT_EFI_ERROR (Status
);
725 Variable Driver main entry point. The Variable driver places the 4 EFI
726 runtime services in the EFI System Table and installs arch protocols
727 for variable read and write services being available. It also registers
728 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
730 @param[in] ImageHandle The firmware allocated handle for the EFI image.
731 @param[in] SystemTable A pointer to the EFI System Table.
733 @retval EFI_SUCCESS Variable service successfully initialized.
738 VariableServiceInitialize (
739 IN EFI_HANDLE ImageHandle
,
740 IN EFI_SYSTEM_TABLE
*SystemTable
744 EFI_HANDLE VariableHandle
;
745 VOID
*SmmFtwRegistration
;
746 EFI_SMM_ACCESS2_PROTOCOL
*SmmAccess
;
750 // Variable initialize.
752 Status
= VariableCommonInitialize ();
753 ASSERT_EFI_ERROR (Status
);
756 // Install the Smm Variable Protocol on a new handle.
758 VariableHandle
= NULL
;
759 Status
= gSmst
->SmmInstallProtocolInterface (
761 &gEfiSmmVariableProtocolGuid
,
762 EFI_NATIVE_INTERFACE
,
765 ASSERT_EFI_ERROR (Status
);
768 // Get SMRAM information
770 Status
= gBS
->LocateProtocol (&gEfiSmmAccess2ProtocolGuid
, NULL
, (VOID
**)&SmmAccess
);
771 ASSERT_EFI_ERROR (Status
);
774 Status
= SmmAccess
->GetCapabilities (SmmAccess
, &Size
, NULL
);
775 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
777 Status
= gSmst
->SmmAllocatePool (
778 EfiRuntimeServicesData
,
780 (VOID
**)&mSmramRanges
782 ASSERT_EFI_ERROR (Status
);
784 Status
= SmmAccess
->GetCapabilities (SmmAccess
, &Size
, mSmramRanges
);
785 ASSERT_EFI_ERROR (Status
);
787 mSmramRangeCount
= Size
/ sizeof (EFI_SMRAM_DESCRIPTOR
);
790 /// Register SMM variable SMI handler
792 VariableHandle
= NULL
;
793 Status
= gSmst
->SmiHandlerRegister (SmmVariableHandler
, &gEfiSmmVariableProtocolGuid
, &VariableHandle
);
794 ASSERT_EFI_ERROR (Status
);
797 // Notify the variable wrapper driver the variable service is ready
799 Status
= SystemTable
->BootServices
->InstallProtocolInterface (
801 &gEfiSmmVariableProtocolGuid
,
802 EFI_NATIVE_INTERFACE
,
805 ASSERT_EFI_ERROR (Status
);
808 // Register FtwNotificationEvent () notify function.
810 Status
= gSmst
->SmmRegisterProtocolNotify (
811 &gEfiSmmFaultTolerantWriteProtocolGuid
,
812 SmmFtwNotificationEvent
,
815 ASSERT_EFI_ERROR (Status
);
817 SmmFtwNotificationEvent (NULL
, NULL
, NULL
);