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