1 /** @file
2   Implement all four UEFI Runtime Variable services for the nonvolatile
3   and volatile storage space and install variable architecture protocol
4   based on SMM variable module.
5 
6   Caution: This module requires additional review when modified.
7   This driver will have external input - variable data.
8   This external input must be validated carefully to avoid security issue like
9   buffer overflow, integer overflow.
10 
11   RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
12   to receive data buffer. The size should be checked carefully.
13 
14   InitCommunicateBuffer() is really function to check the variable data size.
15 
16 Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>
17 SPDX-License-Identifier: BSD-2-Clause-Patent
18 
19 **/
20 #include <PiDxe.h>
21 #include <Protocol/VariableWrite.h>
22 #include <Protocol/Variable.h>
23 #include <Protocol/SmmCommunication.h>
24 #include <Protocol/SmmVariable.h>
25 #include <Protocol/VariableLock.h>
26 #include <Protocol/VarCheck.h>
27 
28 #include <Library/UefiBootServicesTableLib.h>
29 #include <Library/UefiRuntimeServicesTableLib.h>
30 #include <Library/MemoryAllocationLib.h>
31 #include <Library/UefiDriverEntryPoint.h>
32 #include <Library/UefiRuntimeLib.h>
33 #include <Library/BaseMemoryLib.h>
34 #include <Library/DebugLib.h>
35 #include <Library/UefiLib.h>
36 #include <Library/BaseLib.h>
37 
38 #include <Guid/EventGroup.h>
39 #include <Guid/SmmVariableCommon.h>
40 
41 #include "PrivilegePolymorphic.h"
42 
43 EFI_HANDLE                       mHandle                    = NULL;
44 EFI_SMM_VARIABLE_PROTOCOL       *mSmmVariable               = NULL;
45 EFI_EVENT                        mVirtualAddressChangeEvent = NULL;
46 EFI_SMM_COMMUNICATION_PROTOCOL  *mSmmCommunication          = NULL;
47 UINT8                           *mVariableBuffer            = NULL;
48 UINT8                           *mVariableBufferPhysical    = NULL;
49 UINTN                            mVariableBufferSize;
50 UINTN                            mVariableBufferPayloadSize;
51 EFI_LOCK                         mVariableServicesLock;
52 EDKII_VARIABLE_LOCK_PROTOCOL     mVariableLock;
53 EDKII_VAR_CHECK_PROTOCOL         mVarCheck;
54 
55 /**
56   Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
57   Record their initial State when variable write service is ready.
58 
59 **/
60 VOID
61 EFIAPI
62 RecordSecureBootPolicyVarData(
63   VOID
64   );
65 
66 /**
67   Acquires lock only at boot time. Simply returns at runtime.
68 
69   This is a temperary function that will be removed when
70   EfiAcquireLock() in UefiLib can handle the call in UEFI
71   Runtimer driver in RT phase.
72   It calls EfiAcquireLock() at boot time, and simply returns
73   at runtime.
74 
75   @param  Lock         A pointer to the lock to acquire.
76 
77 **/
78 VOID
AcquireLockOnlyAtBootTime(IN EFI_LOCK * Lock)79 AcquireLockOnlyAtBootTime (
80   IN EFI_LOCK                             *Lock
81   )
82 {
83   if (!EfiAtRuntime ()) {
84     EfiAcquireLock (Lock);
85   }
86 }
87 
88 /**
89   Releases lock only at boot time. Simply returns at runtime.
90 
91   This is a temperary function which will be removed when
92   EfiReleaseLock() in UefiLib can handle the call in UEFI
93   Runtimer driver in RT phase.
94   It calls EfiReleaseLock() at boot time and simply returns
95   at runtime.
96 
97   @param  Lock         A pointer to the lock to release.
98 
99 **/
100 VOID
ReleaseLockOnlyAtBootTime(IN EFI_LOCK * Lock)101 ReleaseLockOnlyAtBootTime (
102   IN EFI_LOCK                             *Lock
103   )
104 {
105   if (!EfiAtRuntime ()) {
106     EfiReleaseLock (Lock);
107   }
108 }
109 
110 /**
111   Initialize the communicate buffer using DataSize and Function.
112 
113   The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
114   DataSize.
115 
116   Caution: This function may receive untrusted input.
117   The data size external input, so this function will validate it carefully to avoid buffer overflow.
118 
119   @param[out]      DataPtr          Points to the data in the communicate buffer.
120   @param[in]       DataSize         The data size to send to SMM.
121   @param[in]       Function         The function number to initialize the communicate header.
122 
123   @retval EFI_INVALID_PARAMETER     The data size is too big.
124   @retval EFI_SUCCESS               Find the specified variable.
125 
126 **/
127 EFI_STATUS
InitCommunicateBuffer(OUT VOID ** DataPtr OPTIONAL,IN UINTN DataSize,IN UINTN Function)128 InitCommunicateBuffer (
129   OUT     VOID                              **DataPtr OPTIONAL,
130   IN      UINTN                             DataSize,
131   IN      UINTN                             Function
132   )
133 {
134   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
135   SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;
136 
137 
138   if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {
139     return EFI_INVALID_PARAMETER;
140   }
141 
142   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
143   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
144   SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
145 
146   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
147   SmmVariableFunctionHeader->Function = Function;
148   if (DataPtr != NULL) {
149     *DataPtr = SmmVariableFunctionHeader->Data;
150   }
151 
152   return EFI_SUCCESS;
153 }
154 
155 
156 /**
157   Send the data in communicate buffer to SMM.
158 
159   @param[in]   DataSize               This size of the function header and the data.
160 
161   @retval      EFI_SUCCESS            Success is returned from the functin in SMM.
162   @retval      Others                 Failure is returned from the function in SMM.
163 
164 **/
165 EFI_STATUS
SendCommunicateBuffer(IN UINTN DataSize)166 SendCommunicateBuffer (
167   IN      UINTN                             DataSize
168   )
169 {
170   EFI_STATUS                                Status;
171   UINTN                                     CommSize;
172   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
173   SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;
174 
175   CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;
176   Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);
177   ASSERT_EFI_ERROR (Status);
178 
179   SmmCommunicateHeader      = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;
180   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;
181   return  SmmVariableFunctionHeader->ReturnStatus;
182 }
183 
184 /**
185   Mark a variable that will become read-only after leaving the DXE phase of execution.
186 
187   @param[in] This          The VARIABLE_LOCK_PROTOCOL instance.
188   @param[in] VariableName  A pointer to the variable name that will be made read-only subsequently.
189   @param[in] VendorGuid    A pointer to the vendor GUID that will be made read-only subsequently.
190 
191   @retval EFI_SUCCESS           The variable specified by the VariableName and the VendorGuid was marked
192                                 as pending to be read-only.
193   @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
194                                 Or VariableName is an empty string.
195   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
196                                 already been signaled.
197   @retval EFI_OUT_OF_RESOURCES  There is not enough resource to hold the lock request.
198 **/
199 EFI_STATUS
200 EFIAPI
VariableLockRequestToLock(IN CONST EDKII_VARIABLE_LOCK_PROTOCOL * This,IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid)201 VariableLockRequestToLock (
202   IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,
203   IN       CHAR16                       *VariableName,
204   IN       EFI_GUID                     *VendorGuid
205   )
206 {
207   EFI_STATUS                                Status;
208   UINTN                                     VariableNameSize;
209   UINTN                                     PayloadSize;
210   SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE    *VariableToLock;
211 
212   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
213     return EFI_INVALID_PARAMETER;
214   }
215 
216   VariableNameSize = StrSize (VariableName);
217   VariableToLock   = NULL;
218 
219   //
220   // If VariableName exceeds SMM payload limit. Return failure
221   //
222   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {
223     return EFI_INVALID_PARAMETER;
224   }
225 
226   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
227 
228   //
229   // Init the communicate buffer. The buffer data size is:
230   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
231   //
232   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;
233   Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);
234   if (EFI_ERROR (Status)) {
235     goto Done;
236   }
237   ASSERT (VariableToLock != NULL);
238 
239   CopyGuid (&VariableToLock->Guid, VendorGuid);
240   VariableToLock->NameSize = VariableNameSize;
241   CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);
242 
243   //
244   // Send data to SMM.
245   //
246   Status = SendCommunicateBuffer (PayloadSize);
247 
248 Done:
249   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
250   return Status;
251 }
252 
253 /**
254   Register SetVariable check handler.
255 
256   @param[in] Handler            Pointer to check handler.
257 
258   @retval EFI_SUCCESS           The SetVariable check handler was registered successfully.
259   @retval EFI_INVALID_PARAMETER Handler is NULL.
260   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
261                                 already been signaled.
262   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the SetVariable check handler register request.
263   @retval EFI_UNSUPPORTED       This interface is not implemented.
264                                 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
265 
266 **/
267 EFI_STATUS
268 EFIAPI
VarCheckRegisterSetVariableCheckHandler(IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler)269 VarCheckRegisterSetVariableCheckHandler (
270   IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER   Handler
271   )
272 {
273   return EFI_UNSUPPORTED;
274 }
275 
276 /**
277   Variable property set.
278 
279   @param[in] Name               Pointer to the variable name.
280   @param[in] Guid               Pointer to the vendor GUID.
281   @param[in] VariableProperty   Pointer to the input variable property.
282 
283   @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was set successfully.
284   @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
285                                 or the fields of VariableProperty are not valid.
286   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
287                                 already been signaled.
288   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the variable property set request.
289 
290 **/
291 EFI_STATUS
292 EFIAPI
VarCheckVariablePropertySet(IN CHAR16 * Name,IN EFI_GUID * Guid,IN VAR_CHECK_VARIABLE_PROPERTY * VariableProperty)293 VarCheckVariablePropertySet (
294   IN CHAR16                         *Name,
295   IN EFI_GUID                       *Guid,
296   IN VAR_CHECK_VARIABLE_PROPERTY    *VariableProperty
297   )
298 {
299   EFI_STATUS                                Status;
300   UINTN                                     VariableNameSize;
301   UINTN                                     PayloadSize;
302   SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
303 
304   if (Name == NULL || Name[0] == 0 || Guid == NULL) {
305     return EFI_INVALID_PARAMETER;
306   }
307 
308   if (VariableProperty == NULL) {
309     return EFI_INVALID_PARAMETER;
310   }
311 
312   if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {
313     return EFI_INVALID_PARAMETER;
314   }
315 
316   VariableNameSize = StrSize (Name);
317   CommVariableProperty = NULL;
318 
319   //
320   // If VariableName exceeds SMM payload limit. Return failure
321   //
322   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
323     return EFI_INVALID_PARAMETER;
324   }
325 
326   AcquireLockOnlyAtBootTime (&mVariableServicesLock);
327 
328   //
329   // Init the communicate buffer. The buffer data size is:
330   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
331   //
332   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
333   Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);
334   if (EFI_ERROR (Status)) {
335     goto Done;
336   }
337   ASSERT (CommVariableProperty != NULL);
338 
339   CopyGuid (&CommVariableProperty->Guid, Guid);
340   CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));
341   CommVariableProperty->NameSize = VariableNameSize;
342   CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
343 
344   //
345   // Send data to SMM.
346   //
347   Status = SendCommunicateBuffer (PayloadSize);
348 
349 Done:
350   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
351   return Status;
352 }
353 
354 /**
355   Variable property get.
356 
357   @param[in]  Name              Pointer to the variable name.
358   @param[in]  Guid              Pointer to the vendor GUID.
359   @param[out] VariableProperty  Pointer to the output variable property.
360 
361   @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was got successfully.
362   @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
363   @retval EFI_NOT_FOUND         The property of variable specified by the Name and Guid was not found.
364 
365 **/
366 EFI_STATUS
367 EFIAPI
VarCheckVariablePropertyGet(IN CHAR16 * Name,IN EFI_GUID * Guid,OUT VAR_CHECK_VARIABLE_PROPERTY * VariableProperty)368 VarCheckVariablePropertyGet (
369   IN CHAR16                         *Name,
370   IN EFI_GUID                       *Guid,
371   OUT VAR_CHECK_VARIABLE_PROPERTY   *VariableProperty
372   )
373 {
374   EFI_STATUS                                Status;
375   UINTN                                     VariableNameSize;
376   UINTN                                     PayloadSize;
377   SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;
378 
379   if (Name == NULL || Name[0] == 0 || Guid == NULL) {
380     return EFI_INVALID_PARAMETER;
381   }
382 
383   if (VariableProperty == NULL) {
384     return EFI_INVALID_PARAMETER;
385   }
386 
387   VariableNameSize = StrSize (Name);
388   CommVariableProperty = NULL;
389 
390   //
391   // If VariableName exceeds SMM payload limit. Return failure
392   //
393   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {
394     return EFI_INVALID_PARAMETER;
395   }
396 
397   AcquireLockOnlyAtBootTime (&mVariableServicesLock);
398 
399   //
400   // Init the communicate buffer. The buffer data size is:
401   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
402   //
403   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;
404   Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);
405   if (EFI_ERROR (Status)) {
406     goto Done;
407   }
408   ASSERT (CommVariableProperty != NULL);
409 
410   CopyGuid (&CommVariableProperty->Guid, Guid);
411   CommVariableProperty->NameSize = VariableNameSize;
412   CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);
413 
414   //
415   // Send data to SMM.
416   //
417   Status = SendCommunicateBuffer (PayloadSize);
418   if (Status == EFI_SUCCESS) {
419     CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));
420   }
421 
422 Done:
423   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
424   return Status;
425 }
426 
427 /**
428   This code finds variable in storage blocks (Volatile or Non-Volatile).
429 
430   Caution: This function may receive untrusted input.
431   The data size is external input, so this function will validate it carefully to avoid buffer overflow.
432 
433   @param[in]      VariableName       Name of Variable to be found.
434   @param[in]      VendorGuid         Variable vendor GUID.
435   @param[out]     Attributes         Attribute value of the variable found.
436   @param[in, out] DataSize           Size of Data found. If size is less than the
437                                      data, this value contains the required size.
438   @param[out]     Data               Data pointer.
439 
440   @retval EFI_INVALID_PARAMETER      Invalid parameter.
441   @retval EFI_SUCCESS                Find the specified variable.
442   @retval EFI_NOT_FOUND              Not found.
443   @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.
444 
445 **/
446 EFI_STATUS
447 EFIAPI
RuntimeServiceGetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,OUT UINT32 * Attributes OPTIONAL,IN OUT UINTN * DataSize,OUT VOID * Data)448 RuntimeServiceGetVariable (
449   IN      CHAR16                            *VariableName,
450   IN      EFI_GUID                          *VendorGuid,
451   OUT     UINT32                            *Attributes OPTIONAL,
452   IN OUT  UINTN                             *DataSize,
453   OUT     VOID                              *Data
454   )
455 {
456   EFI_STATUS                                Status;
457   UINTN                                     PayloadSize;
458   SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;
459   UINTN                                     TempDataSize;
460   UINTN                                     VariableNameSize;
461 
462   if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
463     return EFI_INVALID_PARAMETER;
464   }
465 
466   TempDataSize          = *DataSize;
467   VariableNameSize      = StrSize (VariableName);
468   SmmVariableHeader     = NULL;
469 
470   //
471   // If VariableName exceeds SMM payload limit. Return failure
472   //
473   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
474     return EFI_INVALID_PARAMETER;
475   }
476 
477   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
478 
479   //
480   // Init the communicate buffer. The buffer data size is:
481   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
482   //
483   if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {
484     //
485     // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
486     //
487     TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;
488   }
489   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;
490 
491   Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
492   if (EFI_ERROR (Status)) {
493     goto Done;
494   }
495   ASSERT (SmmVariableHeader != NULL);
496 
497   CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
498   SmmVariableHeader->DataSize   = TempDataSize;
499   SmmVariableHeader->NameSize   = VariableNameSize;
500   if (Attributes == NULL) {
501     SmmVariableHeader->Attributes = 0;
502   } else {
503     SmmVariableHeader->Attributes = *Attributes;
504   }
505   CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
506 
507   //
508   // Send data to SMM.
509   //
510   Status = SendCommunicateBuffer (PayloadSize);
511 
512   //
513   // Get data from SMM.
514   //
515   if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
516     //
517     // SMM CommBuffer DataSize can be a trimed value
518     // Only update DataSize when needed
519     //
520     *DataSize = SmmVariableHeader->DataSize;
521   }
522   if (Attributes != NULL) {
523     *Attributes = SmmVariableHeader->Attributes;
524   }
525 
526   if (EFI_ERROR (Status)) {
527     goto Done;
528   }
529 
530   if (Data != NULL) {
531     CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
532   } else {
533     Status = EFI_INVALID_PARAMETER;
534   }
535 
536 Done:
537   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
538   return Status;
539 }
540 
541 
542 /**
543   This code Finds the Next available variable.
544 
545   @param[in, out] VariableNameSize   Size of the variable name.
546   @param[in, out] VariableName       Pointer to variable name.
547   @param[in, out] VendorGuid         Variable Vendor Guid.
548 
549   @retval EFI_INVALID_PARAMETER      Invalid parameter.
550   @retval EFI_SUCCESS                Find the specified variable.
551   @retval EFI_NOT_FOUND              Not found.
552   @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.
553 
554 **/
555 EFI_STATUS
556 EFIAPI
RuntimeServiceGetNextVariableName(IN OUT UINTN * VariableNameSize,IN OUT CHAR16 * VariableName,IN OUT EFI_GUID * VendorGuid)557 RuntimeServiceGetNextVariableName (
558   IN OUT  UINTN                             *VariableNameSize,
559   IN OUT  CHAR16                            *VariableName,
560   IN OUT  EFI_GUID                          *VendorGuid
561   )
562 {
563   EFI_STATUS                                      Status;
564   UINTN                                           PayloadSize;
565   SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
566   UINTN                                           OutVariableNameSize;
567   UINTN                                           InVariableNameSize;
568 
569   if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
570     return EFI_INVALID_PARAMETER;
571   }
572 
573   OutVariableNameSize   = *VariableNameSize;
574   InVariableNameSize    = StrSize (VariableName);
575   SmmGetNextVariableName = NULL;
576 
577   //
578   // If input string exceeds SMM payload limit. Return failure
579   //
580   if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
581     return EFI_INVALID_PARAMETER;
582   }
583 
584   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
585 
586   //
587   // Init the communicate buffer. The buffer data size is:
588   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
589   //
590   if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
591     //
592     // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
593     //
594     OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
595   }
596   //
597   // Payload should be Guid + NameSize + MAX of Input & Output buffer
598   //
599   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);
600 
601   Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
602   if (EFI_ERROR (Status)) {
603     goto Done;
604   }
605   ASSERT (SmmGetNextVariableName != NULL);
606 
607   //
608   // SMM comm buffer->NameSize is buffer size for return string
609   //
610   SmmGetNextVariableName->NameSize = OutVariableNameSize;
611 
612   CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
613   //
614   // Copy whole string
615   //
616   CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);
617   if (OutVariableNameSize > InVariableNameSize) {
618     ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);
619   }
620 
621   //
622   // Send data to SMM
623   //
624   Status = SendCommunicateBuffer (PayloadSize);
625 
626   //
627   // Get data from SMM.
628   //
629   if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
630     //
631     // SMM CommBuffer NameSize can be a trimed value
632     // Only update VariableNameSize when needed
633     //
634     *VariableNameSize = SmmGetNextVariableName->NameSize;
635   }
636   if (EFI_ERROR (Status)) {
637     goto Done;
638   }
639 
640   CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
641   CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
642 
643 Done:
644   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
645   return Status;
646 }
647 
648 /**
649   This code sets variable in storage blocks (Volatile or Non-Volatile).
650 
651   Caution: This function may receive untrusted input.
652   The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
653 
654   @param[in] VariableName                 Name of Variable to be found.
655   @param[in] VendorGuid                   Variable vendor GUID.
656   @param[in] Attributes                   Attribute value of the variable found
657   @param[in] DataSize                     Size of Data found. If size is less than the
658                                           data, this value contains the required size.
659   @param[in] Data                         Data pointer.
660 
661   @retval EFI_INVALID_PARAMETER           Invalid parameter.
662   @retval EFI_SUCCESS                     Set successfully.
663   @retval EFI_OUT_OF_RESOURCES            Resource not enough to set variable.
664   @retval EFI_NOT_FOUND                   Not found.
665   @retval EFI_WRITE_PROTECTED             Variable is read-only.
666 
667 **/
668 EFI_STATUS
669 EFIAPI
RuntimeServiceSetVariable(IN CHAR16 * VariableName,IN EFI_GUID * VendorGuid,IN UINT32 Attributes,IN UINTN DataSize,IN VOID * Data)670 RuntimeServiceSetVariable (
671   IN CHAR16                                 *VariableName,
672   IN EFI_GUID                               *VendorGuid,
673   IN UINT32                                 Attributes,
674   IN UINTN                                  DataSize,
675   IN VOID                                   *Data
676   )
677 {
678   EFI_STATUS                                Status;
679   UINTN                                     PayloadSize;
680   SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;
681   UINTN                                     VariableNameSize;
682 
683   //
684   // Check input parameters.
685   //
686   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
687     return EFI_INVALID_PARAMETER;
688   }
689 
690   if (DataSize != 0 && Data == NULL) {
691     return EFI_INVALID_PARAMETER;
692   }
693 
694   VariableNameSize      = StrSize (VariableName);
695   SmmVariableHeader     = NULL;
696 
697   //
698   // If VariableName or DataSize exceeds SMM payload limit. Return failure
699   //
700   if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
701       (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){
702     return EFI_INVALID_PARAMETER;
703   }
704 
705   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
706 
707   //
708   // Init the communicate buffer. The buffer data size is:
709   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
710   //
711   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;
712   Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);
713   if (EFI_ERROR (Status)) {
714     goto Done;
715   }
716   ASSERT (SmmVariableHeader != NULL);
717 
718   CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);
719   SmmVariableHeader->DataSize   = DataSize;
720   SmmVariableHeader->NameSize   = VariableNameSize;
721   SmmVariableHeader->Attributes = Attributes;
722   CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
723   CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
724 
725   //
726   // Send data to SMM.
727   //
728   Status = SendCommunicateBuffer (PayloadSize);
729 
730 Done:
731   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
732 
733   if (!EfiAtRuntime ()) {
734     if (!EFI_ERROR (Status)) {
735       SecureBootHook (
736         VariableName,
737         VendorGuid
738         );
739     }
740   }
741   return Status;
742 }
743 
744 
745 /**
746   This code returns information about the EFI variables.
747 
748   @param[in]  Attributes                   Attributes bitmask to specify the type of variables
749                                            on which to return information.
750   @param[out] MaximumVariableStorageSize   Pointer to the maximum size of the storage space available
751                                            for the EFI variables associated with the attributes specified.
752   @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
753                                            for EFI variables associated with the attributes specified.
754   @param[out] MaximumVariableSize          Pointer to the maximum size of an individual EFI variables
755                                            associated with the attributes specified.
756 
757   @retval EFI_INVALID_PARAMETER            An invalid combination of attribute bits was supplied.
758   @retval EFI_SUCCESS                      Query successfully.
759   @retval EFI_UNSUPPORTED                  The attribute is not supported on this platform.
760 
761 **/
762 EFI_STATUS
763 EFIAPI
RuntimeServiceQueryVariableInfo(IN UINT32 Attributes,OUT UINT64 * MaximumVariableStorageSize,OUT UINT64 * RemainingVariableStorageSize,OUT UINT64 * MaximumVariableSize)764 RuntimeServiceQueryVariableInfo (
765   IN  UINT32                                Attributes,
766   OUT UINT64                                *MaximumVariableStorageSize,
767   OUT UINT64                                *RemainingVariableStorageSize,
768   OUT UINT64                                *MaximumVariableSize
769   )
770 {
771   EFI_STATUS                                Status;
772   UINTN                                     PayloadSize;
773   SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;
774 
775   SmmQueryVariableInfo = NULL;
776 
777   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
778     return EFI_INVALID_PARAMETER;
779   }
780 
781   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
782 
783   //
784   // Init the communicate buffer. The buffer data size is:
785   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
786   //
787   PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
788   Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
789   if (EFI_ERROR (Status)) {
790     goto Done;
791   }
792   ASSERT (SmmQueryVariableInfo != NULL);
793 
794   SmmQueryVariableInfo->Attributes  = Attributes;
795 
796   //
797   // Send data to SMM.
798   //
799   Status = SendCommunicateBuffer (PayloadSize);
800   if (EFI_ERROR (Status)) {
801     goto Done;
802   }
803 
804   //
805   // Get data from SMM.
806   //
807   *MaximumVariableSize          = SmmQueryVariableInfo->MaximumVariableSize;
808   *MaximumVariableStorageSize   = SmmQueryVariableInfo->MaximumVariableStorageSize;
809   *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
810 
811 Done:
812   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
813   return Status;
814 }
815 
816 
817 /**
818   Exit Boot Services Event notification handler.
819 
820   Notify SMM variable driver about the event.
821 
822   @param[in]  Event     Event whose notification function is being invoked.
823   @param[in]  Context   Pointer to the notification function's context.
824 
825 **/
826 VOID
827 EFIAPI
OnExitBootServices(IN EFI_EVENT Event,IN VOID * Context)828 OnExitBootServices (
829   IN      EFI_EVENT                         Event,
830   IN      VOID                              *Context
831   )
832 {
833   //
834   // Init the communicate buffer. The buffer data size is:
835   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
836   //
837   InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
838 
839   //
840   // Send data to SMM.
841   //
842   SendCommunicateBuffer (0);
843 }
844 
845 
846 /**
847   On Ready To Boot Services Event notification handler.
848 
849   Notify SMM variable driver about the event.
850 
851   @param[in]  Event     Event whose notification function is being invoked
852   @param[in]  Context   Pointer to the notification function's context
853 
854 **/
855 VOID
856 EFIAPI
OnReadyToBoot(IN EFI_EVENT Event,IN VOID * Context)857 OnReadyToBoot (
858   IN      EFI_EVENT                         Event,
859   IN      VOID                              *Context
860   )
861 {
862   //
863   // Init the communicate buffer. The buffer data size is:
864   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
865   //
866   InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
867 
868   //
869   // Send data to SMM.
870   //
871   SendCommunicateBuffer (0);
872 
873   gBS->CloseEvent (Event);
874 }
875 
876 
877 /**
878   Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
879 
880   This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
881   It convers pointer to new virtual address.
882 
883   @param[in]  Event        Event whose notification function is being invoked.
884   @param[in]  Context      Pointer to the notification function's context.
885 
886 **/
887 VOID
888 EFIAPI
VariableAddressChangeEvent(IN EFI_EVENT Event,IN VOID * Context)889 VariableAddressChangeEvent (
890   IN EFI_EVENT                              Event,
891   IN VOID                                   *Context
892   )
893 {
894   EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);
895   EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
896 }
897 
898 /**
899   This code gets variable payload size.
900 
901   @param[out] VariablePayloadSize   Output pointer to variable payload size.
902 
903   @retval EFI_SUCCESS               Get successfully.
904   @retval Others                    Get unsuccessfully.
905 
906 **/
907 EFI_STATUS
908 EFIAPI
GetVariablePayloadSize(OUT UINTN * VariablePayloadSize)909 GetVariablePayloadSize (
910   OUT UINTN                         *VariablePayloadSize
911   )
912 {
913   EFI_STATUS                                Status;
914   SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;
915   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;
916   SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;
917   UINTN                                     CommSize;
918   UINT8                                     *CommBuffer;
919 
920   SmmGetPayloadSize = NULL;
921   CommBuffer = NULL;
922 
923   if(VariablePayloadSize == NULL) {
924     return EFI_INVALID_PARAMETER;
925   }
926 
927   AcquireLockOnlyAtBootTime(&mVariableServicesLock);
928 
929   //
930   // Init the communicate buffer. The buffer data size is:
931   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
932   //
933   CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
934   CommBuffer = AllocateZeroPool (CommSize);
935   if (CommBuffer == NULL) {
936     Status = EFI_OUT_OF_RESOURCES;
937     goto Done;
938   }
939 
940   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;
941   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);
942   SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
943 
944   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;
945   SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;
946   SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;
947 
948   //
949   // Send data to SMM.
950   //
951   Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);
952   ASSERT_EFI_ERROR (Status);
953 
954   Status = SmmVariableFunctionHeader->ReturnStatus;
955   if (EFI_ERROR (Status)) {
956     goto Done;
957   }
958 
959   //
960   // Get data from SMM.
961   //
962   *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;
963 
964 Done:
965   if (CommBuffer != NULL) {
966     FreePool (CommBuffer);
967   }
968   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
969   return Status;
970 }
971 
972 /**
973   Initialize variable service and install Variable Architectural protocol.
974 
975   @param[in] Event    Event whose notification function is being invoked.
976   @param[in] Context  Pointer to the notification function's context.
977 
978 **/
979 VOID
980 EFIAPI
SmmVariableReady(IN EFI_EVENT Event,IN VOID * Context)981 SmmVariableReady (
982   IN  EFI_EVENT                             Event,
983   IN  VOID                                  *Context
984   )
985 {
986   EFI_STATUS                                Status;
987 
988   Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);
989   if (EFI_ERROR (Status)) {
990     return;
991   }
992 
993   Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
994   ASSERT_EFI_ERROR (Status);
995 
996   //
997   // Allocate memory for variable communicate buffer.
998   //
999   Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);
1000   ASSERT_EFI_ERROR (Status);
1001   mVariableBufferSize  = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
1002   mVariableBuffer      = AllocateRuntimePool (mVariableBufferSize);
1003   ASSERT (mVariableBuffer != NULL);
1004 
1005   //
1006   // Save the buffer physical address used for SMM conmunication.
1007   //
1008   mVariableBufferPhysical = mVariableBuffer;
1009 
1010   gRT->GetVariable         = RuntimeServiceGetVariable;
1011   gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;
1012   gRT->SetVariable         = RuntimeServiceSetVariable;
1013   gRT->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;
1014 
1015   //
1016   // Install the Variable Architectural Protocol on a new handle.
1017   //
1018   Status = gBS->InstallProtocolInterface (
1019                   &mHandle,
1020                   &gEfiVariableArchProtocolGuid,
1021                   EFI_NATIVE_INTERFACE,
1022                   NULL
1023                   );
1024   ASSERT_EFI_ERROR (Status);
1025 
1026   mVariableLock.RequestToLock = VariableLockRequestToLock;
1027   Status = gBS->InstallMultipleProtocolInterfaces (
1028                   &mHandle,
1029                   &gEdkiiVariableLockProtocolGuid,
1030                   &mVariableLock,
1031                   NULL
1032                   );
1033   ASSERT_EFI_ERROR (Status);
1034 
1035   mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;
1036   mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;
1037   mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;
1038   Status = gBS->InstallMultipleProtocolInterfaces (
1039                   &mHandle,
1040                   &gEdkiiVarCheckProtocolGuid,
1041                   &mVarCheck,
1042                   NULL
1043                   );
1044   ASSERT_EFI_ERROR (Status);
1045 
1046   gBS->CloseEvent (Event);
1047 }
1048 
1049 
1050 /**
1051   SMM Non-Volatile variable write service is ready notify event handler.
1052 
1053   @param[in] Event    Event whose notification function is being invoked.
1054   @param[in] Context  Pointer to the notification function's context.
1055 
1056 **/
1057 VOID
1058 EFIAPI
SmmVariableWriteReady(IN EFI_EVENT Event,IN VOID * Context)1059 SmmVariableWriteReady (
1060   IN  EFI_EVENT                             Event,
1061   IN  VOID                                  *Context
1062   )
1063 {
1064   EFI_STATUS                                Status;
1065   VOID                                      *ProtocolOps;
1066 
1067   //
1068   // Check whether the protocol is installed or not.
1069   //
1070   Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);
1071   if (EFI_ERROR (Status)) {
1072     return;
1073   }
1074 
1075   //
1076   // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
1077   // Secure Boot Policy Variable change.  Record their initial value.
1078   //
1079   RecordSecureBootPolicyVarData();
1080 
1081   Status = gBS->InstallProtocolInterface (
1082                   &mHandle,
1083                   &gEfiVariableWriteArchProtocolGuid,
1084                   EFI_NATIVE_INTERFACE,
1085                   NULL
1086                   );
1087   ASSERT_EFI_ERROR (Status);
1088 
1089   gBS->CloseEvent (Event);
1090 }
1091 
1092 
1093 /**
1094   Variable Driver main entry point. The Variable driver places the 4 EFI
1095   runtime services in the EFI System Table and installs arch protocols
1096   for variable read and write services being available. It also registers
1097   a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1098 
1099   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
1100   @param[in] SystemTable    A pointer to the EFI System Table.
1101 
1102   @retval EFI_SUCCESS       Variable service successfully initialized.
1103 
1104 **/
1105 EFI_STATUS
1106 EFIAPI
VariableSmmRuntimeInitialize(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)1107 VariableSmmRuntimeInitialize (
1108   IN EFI_HANDLE                             ImageHandle,
1109   IN EFI_SYSTEM_TABLE                       *SystemTable
1110   )
1111 {
1112   VOID                                      *SmmVariableRegistration;
1113   VOID                                      *SmmVariableWriteRegistration;
1114   EFI_EVENT                                 OnReadyToBootEvent;
1115   EFI_EVENT                                 ExitBootServiceEvent;
1116   EFI_EVENT                                 LegacyBootEvent;
1117 
1118   EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);
1119 
1120   //
1121   // Smm variable service is ready
1122   //
1123   EfiCreateProtocolNotifyEvent (
1124     &gEfiSmmVariableProtocolGuid,
1125     TPL_CALLBACK,
1126     SmmVariableReady,
1127     NULL,
1128     &SmmVariableRegistration
1129     );
1130 
1131   //
1132   // Smm Non-Volatile variable write service is ready
1133   //
1134   EfiCreateProtocolNotifyEvent (
1135     &gSmmVariableWriteGuid,
1136     TPL_CALLBACK,
1137     SmmVariableWriteReady,
1138     NULL,
1139     &SmmVariableWriteRegistration
1140     );
1141 
1142   //
1143   // Register the event to reclaim variable for OS usage.
1144   //
1145   EfiCreateEventReadyToBootEx (
1146     TPL_NOTIFY,
1147     OnReadyToBoot,
1148     NULL,
1149     &OnReadyToBootEvent
1150     );
1151 
1152   //
1153   // Register the event to inform SMM variable that it is at runtime.
1154   //
1155   gBS->CreateEventEx (
1156          EVT_NOTIFY_SIGNAL,
1157          TPL_NOTIFY,
1158          OnExitBootServices,
1159          NULL,
1160          &gEfiEventExitBootServicesGuid,
1161          &ExitBootServiceEvent
1162          );
1163 
1164   //
1165   // Register the event to inform SMM variable that it is at runtime for legacy boot.
1166   // Reuse OnExitBootServices() here.
1167   //
1168   EfiCreateEventLegacyBootEx(
1169     TPL_NOTIFY,
1170     OnExitBootServices,
1171     NULL,
1172     &LegacyBootEvent
1173     );
1174 
1175   //
1176   // Register the event to convert the pointer for runtime.
1177   //
1178   gBS->CreateEventEx (
1179          EVT_NOTIFY_SIGNAL,
1180          TPL_NOTIFY,
1181          VariableAddressChangeEvent,
1182          NULL,
1183          &gEfiEventVirtualAddressChangeGuid,
1184          &mVirtualAddressChangeEvent
1185          );
1186 
1187   return EFI_SUCCESS;
1188 }
1189 
1190