3 Implement all four UEFI Runtime Variable services for the nonvolatile
4 and volatile storage space and install variable architecture protocol
5 based on SMM variable module.
7 Caution: This module requires additional review when modified.
8 This driver will have external input - variable data.
9 This external input must be validated carefully to avoid security issue like
10 buffer overflow, integer overflow.
12 RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
13 to receive data buffer. The size should be checked carefully.
15 InitCommunicateBuffer() is really function to check the variable data size.
17 Copyright (c) 2010 - 2014, 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/VariableWrite.h>
29 #include <Protocol/Variable.h>
30 #include <Protocol/SmmCommunication.h>
31 #include <Protocol/SmmVariable.h>
32 #include <Protocol/VariableLock.h>
34 #include <Library/UefiBootServicesTableLib.h>
35 #include <Library/UefiRuntimeServicesTableLib.h>
36 #include <Library/MemoryAllocationLib.h>
37 #include <Library/UefiDriverEntryPoint.h>
38 #include <Library/UefiRuntimeLib.h>
39 #include <Library/BaseMemoryLib.h>
40 #include <Library/DebugLib.h>
41 #include <Library/PcdLib.h>
42 #include <Library/UefiLib.h>
43 #include <Library/BaseLib.h>
45 #include <Guid/EventGroup.h>
46 #include <Guid/VariableFormat.h>
47 #include <Guid/SmmVariableCommon.h>
49 EFI_HANDLE mHandle
= NULL
;
50 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
= NULL
;
51 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
52 EFI_SMM_COMMUNICATION_PROTOCOL
*mSmmCommunication
= NULL
;
53 UINT8
*mVariableBuffer
= NULL
;
54 UINT8
*mVariableBufferPhysical
= NULL
;
55 UINTN mVariableBufferSize
;
56 UINTN mVariableBufferPayloadSize
;
57 EFI_LOCK mVariableServicesLock
;
58 EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock
;
61 Acquires lock only at boot time. Simply returns at runtime.
63 This is a temperary function that will be removed when
64 EfiAcquireLock() in UefiLib can handle the call in UEFI
65 Runtimer driver in RT phase.
66 It calls EfiAcquireLock() at boot time, and simply returns
69 @param Lock A pointer to the lock to acquire.
73 AcquireLockOnlyAtBootTime (
77 if (!EfiAtRuntime ()) {
78 EfiAcquireLock (Lock
);
83 Releases lock only at boot time. Simply returns at runtime.
85 This is a temperary function which will be removed when
86 EfiReleaseLock() in UefiLib can handle the call in UEFI
87 Runtimer driver in RT phase.
88 It calls EfiReleaseLock() at boot time and simply returns
91 @param Lock A pointer to the lock to release.
95 ReleaseLockOnlyAtBootTime (
99 if (!EfiAtRuntime ()) {
100 EfiReleaseLock (Lock
);
105 Initialize the communicate buffer using DataSize and Function.
107 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
110 Caution: This function may receive untrusted input.
111 The data size external input, so this function will validate it carefully to avoid buffer overflow.
113 @param[out] DataPtr Points to the data in the communicate buffer.
114 @param[in] DataSize The data size to send to SMM.
115 @param[in] Function The function number to initialize the communicate header.
117 @retval EFI_INVALID_PARAMETER The data size is too big.
118 @retval EFI_SUCCESS Find the specified variable.
122 InitCommunicateBuffer (
123 OUT VOID
**DataPtr OPTIONAL
,
128 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
129 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
132 if (DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
> mVariableBufferSize
) {
133 return EFI_INVALID_PARAMETER
;
136 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
137 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
138 SmmCommunicateHeader
->MessageLength
= DataSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
140 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
141 SmmVariableFunctionHeader
->Function
= Function
;
142 if (DataPtr
!= NULL
) {
143 *DataPtr
= SmmVariableFunctionHeader
->Data
;
151 Send the data in communicate buffer to SMM.
153 @param[in] DataSize This size of the function header and the data.
155 @retval EFI_SUCCESS Success is returned from the functin in SMM.
156 @retval Others Failure is returned from the function in SMM.
160 SendCommunicateBuffer (
166 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
167 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
169 CommSize
= DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
170 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, mVariableBufferPhysical
, &CommSize
);
171 ASSERT_EFI_ERROR (Status
);
173 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
174 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
175 return SmmVariableFunctionHeader
->ReturnStatus
;
179 Mark a variable that will become read-only after leaving the DXE phase of execution.
181 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
182 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
183 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
185 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
186 as pending to be read-only.
187 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
188 Or VariableName is an empty string.
189 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
190 already been signaled.
191 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
195 VariableLockRequestToLock (
196 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
197 IN CHAR16
*VariableName
,
198 IN EFI_GUID
*VendorGuid
202 UINTN VariableNameSize
;
204 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
206 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
207 return EFI_INVALID_PARAMETER
;
210 VariableNameSize
= StrSize (VariableName
);
211 VariableToLock
= NULL
;
214 // If VariableName exceeds SMM payload limit. Return failure
216 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
)) {
217 return EFI_INVALID_PARAMETER
;
220 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
223 // Init the communicate buffer. The buffer data size is:
224 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
226 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
) + VariableNameSize
;
227 Status
= InitCommunicateBuffer ((VOID
**) &VariableToLock
, PayloadSize
, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
);
228 if (EFI_ERROR (Status
)) {
231 ASSERT (VariableToLock
!= NULL
);
233 CopyGuid (&VariableToLock
->Guid
, VendorGuid
);
234 VariableToLock
->NameSize
= VariableNameSize
;
235 CopyMem (VariableToLock
->Name
, VariableName
, VariableToLock
->NameSize
);
240 Status
= SendCommunicateBuffer (PayloadSize
);
243 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
248 This code finds variable in storage blocks (Volatile or Non-Volatile).
250 Caution: This function may receive untrusted input.
251 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
253 @param[in] VariableName Name of Variable to be found.
254 @param[in] VendorGuid Variable vendor GUID.
255 @param[out] Attributes Attribute value of the variable found.
256 @param[in, out] DataSize Size of Data found. If size is less than the
257 data, this value contains the required size.
258 @param[out] Data Data pointer.
260 @retval EFI_INVALID_PARAMETER Invalid parameter.
261 @retval EFI_SUCCESS Find the specified variable.
262 @retval EFI_NOT_FOUND Not found.
263 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
268 RuntimeServiceGetVariable (
269 IN CHAR16
*VariableName
,
270 IN EFI_GUID
*VendorGuid
,
271 OUT UINT32
*Attributes OPTIONAL
,
272 IN OUT UINTN
*DataSize
,
278 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
280 UINTN VariableNameSize
;
282 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
283 return EFI_INVALID_PARAMETER
;
286 if ((*DataSize
!= 0) && (Data
== NULL
)) {
287 return EFI_INVALID_PARAMETER
;
290 TempDataSize
= *DataSize
;
291 VariableNameSize
= StrSize (VariableName
);
292 SmmVariableHeader
= NULL
;
295 // If VariableName exceeds SMM payload limit. Return failure
297 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
298 return EFI_INVALID_PARAMETER
;
301 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
304 // Init the communicate buffer. The buffer data size is:
305 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
307 if (TempDataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
) {
309 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
311 TempDataSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
;
313 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ TempDataSize
;
315 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_VARIABLE
);
316 if (EFI_ERROR (Status
)) {
319 ASSERT (SmmVariableHeader
!= NULL
);
321 CopyGuid (&SmmVariableHeader
->Guid
, VendorGuid
);
322 SmmVariableHeader
->DataSize
= TempDataSize
;
323 SmmVariableHeader
->NameSize
= VariableNameSize
;
324 if (Attributes
== NULL
) {
325 SmmVariableHeader
->Attributes
= 0;
327 SmmVariableHeader
->Attributes
= *Attributes
;
329 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
334 Status
= SendCommunicateBuffer (PayloadSize
);
337 // Get data from SMM.
339 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
341 // SMM CommBuffer DataSize can be a trimed value
342 // Only update DataSize when needed
344 *DataSize
= SmmVariableHeader
->DataSize
;
346 if (Attributes
!= NULL
) {
347 *Attributes
= SmmVariableHeader
->Attributes
;
350 if (EFI_ERROR (Status
)) {
354 CopyMem (Data
, (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, SmmVariableHeader
->DataSize
);
357 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
363 This code Finds the Next available variable.
365 @param[in, out] VariableNameSize Size of the variable name.
366 @param[in, out] VariableName Pointer to variable name.
367 @param[in, out] VendorGuid Variable Vendor Guid.
369 @retval EFI_INVALID_PARAMETER Invalid parameter.
370 @retval EFI_SUCCESS Find the specified variable.
371 @retval EFI_NOT_FOUND Not found.
372 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
377 RuntimeServiceGetNextVariableName (
378 IN OUT UINTN
*VariableNameSize
,
379 IN OUT CHAR16
*VariableName
,
380 IN OUT EFI_GUID
*VendorGuid
385 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*SmmGetNextVariableName
;
386 UINTN OutVariableNameSize
;
387 UINTN InVariableNameSize
;
389 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
390 return EFI_INVALID_PARAMETER
;
393 OutVariableNameSize
= *VariableNameSize
;
394 InVariableNameSize
= StrSize (VariableName
);
395 SmmGetNextVariableName
= NULL
;
398 // If input string exceeds SMM payload limit. Return failure
400 if (InVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
401 return EFI_INVALID_PARAMETER
;
404 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
407 // Init the communicate buffer. The buffer data size is:
408 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
410 if (OutVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
412 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
414 OutVariableNameSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
417 // Payload should be Guid + NameSize + MAX of Input & Output buffer
419 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + MAX (OutVariableNameSize
, InVariableNameSize
);
422 Status
= InitCommunicateBuffer ((VOID
**)&SmmGetNextVariableName
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
);
423 if (EFI_ERROR (Status
)) {
426 ASSERT (SmmGetNextVariableName
!= NULL
);
429 // SMM comm buffer->NameSize is buffer size for return string
431 SmmGetNextVariableName
->NameSize
= OutVariableNameSize
;
433 CopyGuid (&SmmGetNextVariableName
->Guid
, VendorGuid
);
437 CopyMem (SmmGetNextVariableName
->Name
, VariableName
, InVariableNameSize
);
438 if (OutVariableNameSize
> InVariableNameSize
) {
439 ZeroMem ((UINT8
*) SmmGetNextVariableName
->Name
+ InVariableNameSize
, OutVariableNameSize
- InVariableNameSize
);
445 Status
= SendCommunicateBuffer (PayloadSize
);
448 // Get data from SMM.
450 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
452 // SMM CommBuffer NameSize can be a trimed value
453 // Only update VariableNameSize when needed
455 *VariableNameSize
= SmmGetNextVariableName
->NameSize
;
457 if (EFI_ERROR (Status
)) {
461 CopyGuid (VendorGuid
, &SmmGetNextVariableName
->Guid
);
462 CopyMem (VariableName
, SmmGetNextVariableName
->Name
, SmmGetNextVariableName
->NameSize
);
465 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
470 This code sets variable in storage blocks (Volatile or Non-Volatile).
472 Caution: This function may receive untrusted input.
473 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
475 @param[in] VariableName Name of Variable to be found.
476 @param[in] VendorGuid Variable vendor GUID.
477 @param[in] Attributes Attribute value of the variable found
478 @param[in] DataSize Size of Data found. If size is less than the
479 data, this value contains the required size.
480 @param[in] Data Data pointer.
482 @retval EFI_INVALID_PARAMETER Invalid parameter.
483 @retval EFI_SUCCESS Set successfully.
484 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
485 @retval EFI_NOT_FOUND Not found.
486 @retval EFI_WRITE_PROTECTED Variable is read-only.
491 RuntimeServiceSetVariable (
492 IN CHAR16
*VariableName
,
493 IN EFI_GUID
*VendorGuid
,
494 IN UINT32 Attributes
,
501 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
502 UINTN VariableNameSize
;
505 // Check input parameters.
507 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
508 return EFI_INVALID_PARAMETER
;
511 if (DataSize
!= 0 && Data
== NULL
) {
512 return EFI_INVALID_PARAMETER
;
515 VariableNameSize
= StrSize (VariableName
);
516 SmmVariableHeader
= NULL
;
519 // If VariableName or DataSize exceeds SMM payload limit. Return failure
521 if ((VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
522 (DataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
)){
523 return EFI_INVALID_PARAMETER
;
526 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
529 // Init the communicate buffer. The buffer data size is:
530 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
532 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ DataSize
;
533 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_SET_VARIABLE
);
534 if (EFI_ERROR (Status
)) {
537 ASSERT (SmmVariableHeader
!= NULL
);
539 CopyGuid ((EFI_GUID
*) &SmmVariableHeader
->Guid
, VendorGuid
);
540 SmmVariableHeader
->DataSize
= DataSize
;
541 SmmVariableHeader
->NameSize
= VariableNameSize
;
542 SmmVariableHeader
->Attributes
= Attributes
;
543 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
544 CopyMem ((UINT8
*) SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, Data
, DataSize
);
549 Status
= SendCommunicateBuffer (PayloadSize
);
552 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
558 This code returns information about the EFI variables.
560 @param[in] Attributes Attributes bitmask to specify the type of variables
561 on which to return information.
562 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
563 for the EFI variables associated with the attributes specified.
564 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
565 for EFI variables associated with the attributes specified.
566 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
567 associated with the attributes specified.
569 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
570 @retval EFI_SUCCESS Query successfully.
571 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
576 RuntimeServiceQueryVariableInfo (
577 IN UINT32 Attributes
,
578 OUT UINT64
*MaximumVariableStorageSize
,
579 OUT UINT64
*RemainingVariableStorageSize
,
580 OUT UINT64
*MaximumVariableSize
585 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*SmmQueryVariableInfo
;
587 SmmQueryVariableInfo
= NULL
;
589 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
590 return EFI_INVALID_PARAMETER
;
593 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
596 // Init the communicate buffer. The buffer data size is:
597 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
599 PayloadSize
= sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
600 Status
= InitCommunicateBuffer ((VOID
**)&SmmQueryVariableInfo
, PayloadSize
, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
);
601 if (EFI_ERROR (Status
)) {
604 ASSERT (SmmQueryVariableInfo
!= NULL
);
606 SmmQueryVariableInfo
->Attributes
= Attributes
;
611 Status
= SendCommunicateBuffer (PayloadSize
);
612 if (EFI_ERROR (Status
)) {
617 // Get data from SMM.
619 *MaximumVariableSize
= SmmQueryVariableInfo
->MaximumVariableSize
;
620 *MaximumVariableStorageSize
= SmmQueryVariableInfo
->MaximumVariableStorageSize
;
621 *RemainingVariableStorageSize
= SmmQueryVariableInfo
->RemainingVariableStorageSize
;
624 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
630 Exit Boot Services Event notification handler.
632 Notify SMM variable driver about the event.
634 @param[in] Event Event whose notification function is being invoked.
635 @param[in] Context Pointer to the notification function's context.
646 // Init the communicate buffer. The buffer data size is:
647 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
649 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
);
654 SendCommunicateBuffer (0);
659 On Ready To Boot Services Event notification handler.
661 Notify SMM variable driver about the event.
663 @param[in] Event Event whose notification function is being invoked
664 @param[in] Context Pointer to the notification function's context
675 // Init the communicate buffer. The buffer data size is:
676 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
678 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT
);
683 SendCommunicateBuffer (0);
688 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
690 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
691 It convers pointer to new virtual address.
693 @param[in] Event Event whose notification function is being invoked.
694 @param[in] Context Pointer to the notification function's context.
699 VariableAddressChangeEvent (
704 EfiConvertPointer (0x0, (VOID
**) &mVariableBuffer
);
705 EfiConvertPointer (0x0, (VOID
**) &mSmmCommunication
);
710 Initialize variable service and install Variable Architectural protocol.
712 @param[in] Event Event whose notification function is being invoked.
713 @param[in] Context Pointer to the notification function's context.
725 Status
= gBS
->LocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
726 if (EFI_ERROR (Status
)) {
730 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &mSmmCommunication
);
731 ASSERT_EFI_ERROR (Status
);
734 // Allocate memory for variable communicate buffer.
736 mVariableBufferPayloadSize
= MAX (PcdGet32 (PcdMaxVariableSize
), PcdGet32 (PcdMaxHardwareErrorVariableSize
)) +
737 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - sizeof (VARIABLE_HEADER
);
738 mVariableBufferSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ mVariableBufferPayloadSize
;
739 mVariableBuffer
= AllocateRuntimePool (mVariableBufferSize
);
740 ASSERT (mVariableBuffer
!= NULL
);
743 // Save the buffer physical address used for SMM conmunication.
745 mVariableBufferPhysical
= mVariableBuffer
;
747 gRT
->GetVariable
= RuntimeServiceGetVariable
;
748 gRT
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
749 gRT
->SetVariable
= RuntimeServiceSetVariable
;
750 gRT
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
753 // Install the Variable Architectural Protocol on a new handle.
755 Status
= gBS
->InstallProtocolInterface (
757 &gEfiVariableArchProtocolGuid
,
758 EFI_NATIVE_INTERFACE
,
761 ASSERT_EFI_ERROR (Status
);
766 SMM Non-Volatile variable write service is ready notify event handler.
768 @param[in] Event Event whose notification function is being invoked.
769 @param[in] Context Pointer to the notification function's context.
774 SmmVariableWriteReady (
783 // Check whether the protocol is installed or not.
785 Status
= gBS
->LocateProtocol (&gSmmVariableWriteGuid
, NULL
, (VOID
**) &ProtocolOps
);
786 if (EFI_ERROR (Status
)) {
790 Status
= gBS
->InstallProtocolInterface (
792 &gEfiVariableWriteArchProtocolGuid
,
793 EFI_NATIVE_INTERFACE
,
796 ASSERT_EFI_ERROR (Status
);
801 Variable Driver main entry point. The Variable driver places the 4 EFI
802 runtime services in the EFI System Table and installs arch protocols
803 for variable read and write services being available. It also registers
804 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
806 @param[in] ImageHandle The firmware allocated handle for the EFI image.
807 @param[in] SystemTable A pointer to the EFI System Table.
809 @retval EFI_SUCCESS Variable service successfully initialized.
814 VariableSmmRuntimeInitialize (
815 IN EFI_HANDLE ImageHandle
,
816 IN EFI_SYSTEM_TABLE
*SystemTable
820 VOID
*SmmVariableRegistration
;
821 VOID
*SmmVariableWriteRegistration
;
822 EFI_EVENT OnReadyToBootEvent
;
823 EFI_EVENT ExitBootServiceEvent
;
825 EfiInitializeLock (&mVariableServicesLock
, TPL_NOTIFY
);
827 mVariableLock
.RequestToLock
= VariableLockRequestToLock
;
828 Status
= gBS
->InstallMultipleProtocolInterfaces (
830 &gEdkiiVariableLockProtocolGuid
,
834 ASSERT_EFI_ERROR (Status
);
837 // Smm variable service is ready
839 EfiCreateProtocolNotifyEvent (
840 &gEfiSmmVariableProtocolGuid
,
844 &SmmVariableRegistration
848 // Smm Non-Volatile variable write service is ready
850 EfiCreateProtocolNotifyEvent (
851 &gSmmVariableWriteGuid
,
853 SmmVariableWriteReady
,
855 &SmmVariableWriteRegistration
859 // Register the event to reclaim variable for OS usage.
861 EfiCreateEventReadyToBootEx (
869 // Register the event to inform SMM variable that it is at runtime.
876 &gEfiEventExitBootServicesGuid
,
877 &ExitBootServiceEvent
881 // Register the event to convert the pointer for runtime.
886 VariableAddressChangeEvent
,
888 &gEfiEventVirtualAddressChangeGuid
,
889 &mVirtualAddressChangeEvent