MdeModulePkg/Variable: Initialize local variable "RtPtrTrack"
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmmRuntimeDxe.c
1 /** @file\r
2   Implement all four UEFI Runtime Variable services for the nonvolatile\r
3   and volatile storage space and install variable architecture protocol\r
4   based on SMM variable module.\r
5 \r
6   Caution: This module requires additional review when modified.\r
7   This driver will have external input - variable data.\r
8   This external input must be validated carefully to avoid security issue like\r
9   buffer overflow, integer overflow.\r
10 \r
11   RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API\r
12   to receive data buffer. The size should be checked carefully.\r
13 \r
14   InitCommunicateBuffer() is really function to check the variable data size.\r
15 \r
16 Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>\r
17 SPDX-License-Identifier: BSD-2-Clause-Patent\r
18 \r
19 **/\r
20 #include <PiDxe.h>\r
21 #include <Protocol/VariableWrite.h>\r
22 #include <Protocol/Variable.h>\r
23 #include <Protocol/SmmCommunication.h>\r
24 #include <Protocol/SmmVariable.h>\r
25 #include <Protocol/VariableLock.h>\r
26 #include <Protocol/VarCheck.h>\r
27 \r
28 #include <Library/UefiBootServicesTableLib.h>\r
29 #include <Library/UefiRuntimeServicesTableLib.h>\r
30 #include <Library/MemoryAllocationLib.h>\r
31 #include <Library/UefiDriverEntryPoint.h>\r
32 #include <Library/UefiRuntimeLib.h>\r
33 #include <Library/BaseMemoryLib.h>\r
34 #include <Library/DebugLib.h>\r
35 #include <Library/UefiLib.h>\r
36 #include <Library/BaseLib.h>\r
37 \r
38 #include <Guid/EventGroup.h>\r
39 #include <Guid/SmmVariableCommon.h>\r
40 \r
41 #include "PrivilegePolymorphic.h"\r
42 #include "VariableParsing.h"\r
43 \r
44 EFI_HANDLE                       mHandle                    = NULL;\r
45 EFI_SMM_VARIABLE_PROTOCOL       *mSmmVariable               = NULL;\r
46 EFI_EVENT                        mVirtualAddressChangeEvent = NULL;\r
47 EFI_SMM_COMMUNICATION_PROTOCOL  *mSmmCommunication          = NULL;\r
48 UINT8                           *mVariableBuffer            = NULL;\r
49 UINT8                           *mVariableBufferPhysical    = NULL;\r
50 VARIABLE_INFO_ENTRY             *mVariableInfo              = NULL;\r
51 VARIABLE_STORE_HEADER           *mVariableRuntimeHobCacheBuffer           = NULL;\r
52 VARIABLE_STORE_HEADER           *mVariableRuntimeNvCacheBuffer            = NULL;\r
53 VARIABLE_STORE_HEADER           *mVariableRuntimeVolatileCacheBuffer      = NULL;\r
54 UINTN                            mVariableBufferSize;\r
55 UINTN                            mVariableRuntimeHobCacheBufferSize;\r
56 UINTN                            mVariableRuntimeNvCacheBufferSize;\r
57 UINTN                            mVariableRuntimeVolatileCacheBufferSize;\r
58 UINTN                            mVariableBufferPayloadSize;\r
59 BOOLEAN                          mVariableRuntimeCachePendingUpdate;\r
60 BOOLEAN                          mVariableRuntimeCacheReadLock;\r
61 BOOLEAN                          mVariableAuthFormat;\r
62 BOOLEAN                          mHobFlushComplete;\r
63 EFI_LOCK                         mVariableServicesLock;\r
64 EDKII_VARIABLE_LOCK_PROTOCOL     mVariableLock;\r
65 EDKII_VAR_CHECK_PROTOCOL         mVarCheck;\r
66 \r
67 /**\r
68   Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).\r
69   Record their initial State when variable write service is ready.\r
70 \r
71 **/\r
72 VOID\r
73 EFIAPI\r
74 RecordSecureBootPolicyVarData(\r
75   VOID\r
76   );\r
77 \r
78 /**\r
79   Acquires lock only at boot time. Simply returns at runtime.\r
80 \r
81   This is a temperary function that will be removed when\r
82   EfiAcquireLock() in UefiLib can handle the call in UEFI\r
83   Runtimer driver in RT phase.\r
84   It calls EfiAcquireLock() at boot time, and simply returns\r
85   at runtime.\r
86 \r
87   @param  Lock         A pointer to the lock to acquire.\r
88 \r
89 **/\r
90 VOID\r
91 AcquireLockOnlyAtBootTime (\r
92   IN EFI_LOCK                             *Lock\r
93   )\r
94 {\r
95   if (!EfiAtRuntime ()) {\r
96     EfiAcquireLock (Lock);\r
97   }\r
98 }\r
99 \r
100 /**\r
101   Releases lock only at boot time. Simply returns at runtime.\r
102 \r
103   This is a temperary function which will be removed when\r
104   EfiReleaseLock() in UefiLib can handle the call in UEFI\r
105   Runtimer driver in RT phase.\r
106   It calls EfiReleaseLock() at boot time and simply returns\r
107   at runtime.\r
108 \r
109   @param  Lock         A pointer to the lock to release.\r
110 \r
111 **/\r
112 VOID\r
113 ReleaseLockOnlyAtBootTime (\r
114   IN EFI_LOCK                             *Lock\r
115   )\r
116 {\r
117   if (!EfiAtRuntime ()) {\r
118     EfiReleaseLock (Lock);\r
119   }\r
120 }\r
121 \r
122 /**\r
123   Return TRUE if ExitBootServices () has been called.\r
124 \r
125   @retval TRUE If ExitBootServices () has been called. FALSE if ExitBootServices () has not been called.\r
126 **/\r
127 BOOLEAN\r
128 AtRuntime (\r
129   VOID\r
130   )\r
131 {\r
132   return EfiAtRuntime ();\r
133 }\r
134 \r
135 /**\r
136   Initialize the variable cache buffer as an empty variable store.\r
137 \r
138   @param[out]     VariableCacheBuffer     A pointer to pointer of a cache variable store.\r
139   @param[in,out]  TotalVariableCacheSize  On input, the minimum size needed for the UEFI variable store cache\r
140                                           buffer that is allocated. On output, the actual size of the buffer allocated.\r
141                                           If TotalVariableCacheSize is zero, a buffer will not be allocated and the\r
142                                           function will return with EFI_SUCCESS.\r
143 \r
144   @retval EFI_SUCCESS             The variable cache was allocated and initialized successfully.\r
145   @retval EFI_INVALID_PARAMETER   A given pointer is NULL or an invalid variable store size was specified.\r
146   @retval EFI_OUT_OF_RESOURCES    Insufficient resources are available to allocate the variable store cache buffer.\r
147 \r
148 **/\r
149 EFI_STATUS\r
150 InitVariableCache (\r
151   OUT    VARIABLE_STORE_HEADER   **VariableCacheBuffer,\r
152   IN OUT UINTN                   *TotalVariableCacheSize\r
153   )\r
154 {\r
155   VARIABLE_STORE_HEADER   *VariableCacheStorePtr;\r
156 \r
157   if (TotalVariableCacheSize == NULL) {\r
158     return EFI_INVALID_PARAMETER;\r
159   }\r
160   if (*TotalVariableCacheSize == 0) {\r
161     return EFI_SUCCESS;\r
162   }\r
163   if (VariableCacheBuffer == NULL || *TotalVariableCacheSize < sizeof (VARIABLE_STORE_HEADER)) {\r
164     return EFI_INVALID_PARAMETER;\r
165   }\r
166   *TotalVariableCacheSize = ALIGN_VALUE (*TotalVariableCacheSize, sizeof (UINT32));\r
167 \r
168   //\r
169   // Allocate NV Storage Cache and initialize it to all 1's (like an erased FV)\r
170   //\r
171   *VariableCacheBuffer =  (VARIABLE_STORE_HEADER *) AllocateRuntimePages (\r
172                             EFI_SIZE_TO_PAGES (*TotalVariableCacheSize)\r
173                             );\r
174   if (*VariableCacheBuffer == NULL) {\r
175     return EFI_OUT_OF_RESOURCES;\r
176   }\r
177   VariableCacheStorePtr = *VariableCacheBuffer;\r
178   SetMem32 ((VOID *) VariableCacheStorePtr, *TotalVariableCacheSize, (UINT32) 0xFFFFFFFF);\r
179 \r
180   ZeroMem ((VOID *) VariableCacheStorePtr, sizeof (VARIABLE_STORE_HEADER));\r
181   VariableCacheStorePtr->Size    = (UINT32) *TotalVariableCacheSize;\r
182   VariableCacheStorePtr->Format  = VARIABLE_STORE_FORMATTED;\r
183   VariableCacheStorePtr->State   = VARIABLE_STORE_HEALTHY;\r
184 \r
185   return EFI_SUCCESS;\r
186 }\r
187 \r
188 /**\r
189   Initialize the communicate buffer using DataSize and Function.\r
190 \r
191   The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +\r
192   DataSize.\r
193 \r
194   Caution: This function may receive untrusted input.\r
195   The data size external input, so this function will validate it carefully to avoid buffer overflow.\r
196 \r
197   @param[out]      DataPtr          Points to the data in the communicate buffer.\r
198   @param[in]       DataSize         The data size to send to SMM.\r
199   @param[in]       Function         The function number to initialize the communicate header.\r
200 \r
201   @retval EFI_INVALID_PARAMETER     The data size is too big.\r
202   @retval EFI_SUCCESS               Find the specified variable.\r
203 \r
204 **/\r
205 EFI_STATUS\r
206 InitCommunicateBuffer (\r
207   OUT     VOID                              **DataPtr OPTIONAL,\r
208   IN      UINTN                             DataSize,\r
209   IN      UINTN                             Function\r
210   )\r
211 {\r
212   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;\r
213   SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;\r
214 \r
215 \r
216   if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {\r
217     return EFI_INVALID_PARAMETER;\r
218   }\r
219 \r
220   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
221   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
222   SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
223 \r
224   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
225   SmmVariableFunctionHeader->Function = Function;\r
226   if (DataPtr != NULL) {\r
227     *DataPtr = SmmVariableFunctionHeader->Data;\r
228   }\r
229 \r
230   return EFI_SUCCESS;\r
231 }\r
232 \r
233 \r
234 /**\r
235   Send the data in communicate buffer to SMM.\r
236 \r
237   @param[in]   DataSize               This size of the function header and the data.\r
238 \r
239   @retval      EFI_SUCCESS            Success is returned from the functin in SMM.\r
240   @retval      Others                 Failure is returned from the function in SMM.\r
241 \r
242 **/\r
243 EFI_STATUS\r
244 SendCommunicateBuffer (\r
245   IN      UINTN                             DataSize\r
246   )\r
247 {\r
248   EFI_STATUS                                Status;\r
249   UINTN                                     CommSize;\r
250   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;\r
251   SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;\r
252 \r
253   CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
254   Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);\r
255   ASSERT_EFI_ERROR (Status);\r
256 \r
257   SmmCommunicateHeader      = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
258   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
259   return  SmmVariableFunctionHeader->ReturnStatus;\r
260 }\r
261 \r
262 /**\r
263   Mark a variable that will become read-only after leaving the DXE phase of execution.\r
264 \r
265   @param[in] This          The VARIABLE_LOCK_PROTOCOL instance.\r
266   @param[in] VariableName  A pointer to the variable name that will be made read-only subsequently.\r
267   @param[in] VendorGuid    A pointer to the vendor GUID that will be made read-only subsequently.\r
268 \r
269   @retval EFI_SUCCESS           The variable specified by the VariableName and the VendorGuid was marked\r
270                                 as pending to be read-only.\r
271   @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.\r
272                                 Or VariableName is an empty string.\r
273   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
274                                 already been signaled.\r
275   @retval EFI_OUT_OF_RESOURCES  There is not enough resource to hold the lock request.\r
276 **/\r
277 EFI_STATUS\r
278 EFIAPI\r
279 VariableLockRequestToLock (\r
280   IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
281   IN       CHAR16                       *VariableName,\r
282   IN       EFI_GUID                     *VendorGuid\r
283   )\r
284 {\r
285   EFI_STATUS                                Status;\r
286   UINTN                                     VariableNameSize;\r
287   UINTN                                     PayloadSize;\r
288   SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE    *VariableToLock;\r
289 \r
290   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
291     return EFI_INVALID_PARAMETER;\r
292   }\r
293 \r
294   VariableNameSize = StrSize (VariableName);\r
295   VariableToLock   = NULL;\r
296 \r
297   //\r
298   // If VariableName exceeds SMM payload limit. Return failure\r
299   //\r
300   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {\r
301     return EFI_INVALID_PARAMETER;\r
302   }\r
303 \r
304   AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
305 \r
306   //\r
307   // Init the communicate buffer. The buffer data size is:\r
308   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
309   //\r
310   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;\r
311   Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);\r
312   if (EFI_ERROR (Status)) {\r
313     goto Done;\r
314   }\r
315   ASSERT (VariableToLock != NULL);\r
316 \r
317   CopyGuid (&VariableToLock->Guid, VendorGuid);\r
318   VariableToLock->NameSize = VariableNameSize;\r
319   CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);\r
320 \r
321   //\r
322   // Send data to SMM.\r
323   //\r
324   Status = SendCommunicateBuffer (PayloadSize);\r
325 \r
326 Done:\r
327   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
328   return Status;\r
329 }\r
330 \r
331 /**\r
332   Register SetVariable check handler.\r
333 \r
334   @param[in] Handler            Pointer to check handler.\r
335 \r
336   @retval EFI_SUCCESS           The SetVariable check handler was registered successfully.\r
337   @retval EFI_INVALID_PARAMETER Handler is NULL.\r
338   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
339                                 already been signaled.\r
340   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the SetVariable check handler register request.\r
341   @retval EFI_UNSUPPORTED       This interface is not implemented.\r
342                                 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.\r
343 \r
344 **/\r
345 EFI_STATUS\r
346 EFIAPI\r
347 VarCheckRegisterSetVariableCheckHandler (\r
348   IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER   Handler\r
349   )\r
350 {\r
351   return EFI_UNSUPPORTED;\r
352 }\r
353 \r
354 /**\r
355   Variable property set.\r
356 \r
357   @param[in] Name               Pointer to the variable name.\r
358   @param[in] Guid               Pointer to the vendor GUID.\r
359   @param[in] VariableProperty   Pointer to the input variable property.\r
360 \r
361   @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was set successfully.\r
362   @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,\r
363                                 or the fields of VariableProperty are not valid.\r
364   @retval EFI_ACCESS_DENIED     EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
365                                 already been signaled.\r
366   @retval EFI_OUT_OF_RESOURCES  There is not enough resource for the variable property set request.\r
367 \r
368 **/\r
369 EFI_STATUS\r
370 EFIAPI\r
371 VarCheckVariablePropertySet (\r
372   IN CHAR16                         *Name,\r
373   IN EFI_GUID                       *Guid,\r
374   IN VAR_CHECK_VARIABLE_PROPERTY    *VariableProperty\r
375   )\r
376 {\r
377   EFI_STATUS                                Status;\r
378   UINTN                                     VariableNameSize;\r
379   UINTN                                     PayloadSize;\r
380   SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
381 \r
382   if (Name == NULL || Name[0] == 0 || Guid == NULL) {\r
383     return EFI_INVALID_PARAMETER;\r
384   }\r
385 \r
386   if (VariableProperty == NULL) {\r
387     return EFI_INVALID_PARAMETER;\r
388   }\r
389 \r
390   if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {\r
391     return EFI_INVALID_PARAMETER;\r
392   }\r
393 \r
394   VariableNameSize = StrSize (Name);\r
395   CommVariableProperty = NULL;\r
396 \r
397   //\r
398   // If VariableName exceeds SMM payload limit. Return failure\r
399   //\r
400   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {\r
401     return EFI_INVALID_PARAMETER;\r
402   }\r
403 \r
404   AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
405 \r
406   //\r
407   // Init the communicate buffer. The buffer data size is:\r
408   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
409   //\r
410   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;\r
411   Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);\r
412   if (EFI_ERROR (Status)) {\r
413     goto Done;\r
414   }\r
415   ASSERT (CommVariableProperty != NULL);\r
416 \r
417   CopyGuid (&CommVariableProperty->Guid, Guid);\r
418   CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));\r
419   CommVariableProperty->NameSize = VariableNameSize;\r
420   CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);\r
421 \r
422   //\r
423   // Send data to SMM.\r
424   //\r
425   Status = SendCommunicateBuffer (PayloadSize);\r
426 \r
427 Done:\r
428   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
429   return Status;\r
430 }\r
431 \r
432 /**\r
433   Variable property get.\r
434 \r
435   @param[in]  Name              Pointer to the variable name.\r
436   @param[in]  Guid              Pointer to the vendor GUID.\r
437   @param[out] VariableProperty  Pointer to the output variable property.\r
438 \r
439   @retval EFI_SUCCESS           The property of variable specified by the Name and Guid was got successfully.\r
440   @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.\r
441   @retval EFI_NOT_FOUND         The property of variable specified by the Name and Guid was not found.\r
442 \r
443 **/\r
444 EFI_STATUS\r
445 EFIAPI\r
446 VarCheckVariablePropertyGet (\r
447   IN CHAR16                         *Name,\r
448   IN EFI_GUID                       *Guid,\r
449   OUT VAR_CHECK_VARIABLE_PROPERTY   *VariableProperty\r
450   )\r
451 {\r
452   EFI_STATUS                                Status;\r
453   UINTN                                     VariableNameSize;\r
454   UINTN                                     PayloadSize;\r
455   SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
456 \r
457   if (Name == NULL || Name[0] == 0 || Guid == NULL) {\r
458     return EFI_INVALID_PARAMETER;\r
459   }\r
460 \r
461   if (VariableProperty == NULL) {\r
462     return EFI_INVALID_PARAMETER;\r
463   }\r
464 \r
465   VariableNameSize = StrSize (Name);\r
466   CommVariableProperty = NULL;\r
467 \r
468   //\r
469   // If VariableName exceeds SMM payload limit. Return failure\r
470   //\r
471   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {\r
472     return EFI_INVALID_PARAMETER;\r
473   }\r
474 \r
475   AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
476 \r
477   //\r
478   // Init the communicate buffer. The buffer data size is:\r
479   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
480   //\r
481   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;\r
482   Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);\r
483   if (EFI_ERROR (Status)) {\r
484     goto Done;\r
485   }\r
486   ASSERT (CommVariableProperty != NULL);\r
487 \r
488   CopyGuid (&CommVariableProperty->Guid, Guid);\r
489   CommVariableProperty->NameSize = VariableNameSize;\r
490   CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);\r
491 \r
492   //\r
493   // Send data to SMM.\r
494   //\r
495   Status = SendCommunicateBuffer (PayloadSize);\r
496   if (Status == EFI_SUCCESS) {\r
497     CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));\r
498   }\r
499 \r
500 Done:\r
501   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
502   return Status;\r
503 }\r
504 \r
505 /**\r
506   Signals SMM to synchronize any pending variable updates with the runtime cache(s).\r
507 \r
508 **/\r
509 VOID\r
510 SyncRuntimeCache (\r
511   VOID\r
512   )\r
513 {\r
514   //\r
515   // Init the communicate buffer. The buffer data size is:\r
516   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
517   //\r
518   InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE);\r
519 \r
520   //\r
521   // Send data to SMM.\r
522   //\r
523   SendCommunicateBuffer (0);\r
524 }\r
525 \r
526 /**\r
527   Check whether a SMI must be triggered to retrieve pending cache updates.\r
528 \r
529   If the variable HOB was finished being flushed since the last check for a runtime cache update, this function\r
530   will prevent the HOB cache from being used for future runtime cache hits.\r
531 \r
532 **/\r
533 VOID\r
534 CheckForRuntimeCacheSync (\r
535   VOID\r
536   )\r
537 {\r
538   if (mVariableRuntimeCachePendingUpdate) {\r
539     SyncRuntimeCache ();\r
540   }\r
541   ASSERT (!mVariableRuntimeCachePendingUpdate);\r
542 \r
543   //\r
544   // The HOB variable data may have finished being flushed in the runtime cache sync update\r
545   //\r
546   if (mHobFlushComplete && mVariableRuntimeHobCacheBuffer != NULL) {\r
547     if (!EfiAtRuntime ()) {\r
548       FreePages (mVariableRuntimeHobCacheBuffer, EFI_SIZE_TO_PAGES (mVariableRuntimeHobCacheBufferSize));\r
549     }\r
550     mVariableRuntimeHobCacheBuffer = NULL;\r
551   }\r
552 }\r
553 \r
554 /**\r
555   Finds the given variable in a runtime cache variable store.\r
556 \r
557   Caution: This function may receive untrusted input.\r
558   The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
559 \r
560   @param[in]      VariableName       Name of Variable to be found.\r
561   @param[in]      VendorGuid         Variable vendor GUID.\r
562   @param[out]     Attributes         Attribute value of the variable found.\r
563   @param[in, out] DataSize           Size of Data found. If size is less than the\r
564                                      data, this value contains the required size.\r
565   @param[out]     Data               Data pointer.\r
566 \r
567   @retval EFI_SUCCESS                Found the specified variable.\r
568   @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
569   @retval EFI_NOT_FOUND              The specified variable could not be found.\r
570 \r
571 **/\r
572 EFI_STATUS\r
573 FindVariableInRuntimeCache (\r
574   IN      CHAR16                            *VariableName,\r
575   IN      EFI_GUID                          *VendorGuid,\r
576   OUT     UINT32                            *Attributes OPTIONAL,\r
577   IN OUT  UINTN                             *DataSize,\r
578   OUT     VOID                              *Data OPTIONAL\r
579   )\r
580 {\r
581   EFI_STATUS              Status;\r
582   UINTN                   TempDataSize;\r
583   VARIABLE_POINTER_TRACK  RtPtrTrack;\r
584   VARIABLE_STORE_TYPE     StoreType;\r
585   VARIABLE_STORE_HEADER   *VariableStoreList[VariableStoreTypeMax];\r
586 \r
587   Status = EFI_NOT_FOUND;\r
588 \r
589   if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
590     return EFI_INVALID_PARAMETER;\r
591   }\r
592 \r
593   ZeroMem (&RtPtrTrack, sizeof (RtPtrTrack));\r
594 \r
595   //\r
596   // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service\r
597   // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent\r
598   // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime\r
599   // cache read lock should always be free when entering this function.\r
600   //\r
601   ASSERT (!mVariableRuntimeCacheReadLock);\r
602 \r
603   mVariableRuntimeCacheReadLock = TRUE;\r
604   CheckForRuntimeCacheSync ();\r
605 \r
606   if (!mVariableRuntimeCachePendingUpdate) {\r
607     //\r
608     // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
609     // The index and attributes mapping must be kept in this order as FindVariable\r
610     // makes use of this mapping to implement search algorithm.\r
611     //\r
612     VariableStoreList[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;\r
613     VariableStoreList[VariableStoreTypeHob]      = mVariableRuntimeHobCacheBuffer;\r
614     VariableStoreList[VariableStoreTypeNv]       = mVariableRuntimeNvCacheBuffer;\r
615 \r
616     for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) {\r
617       if (VariableStoreList[StoreType] == NULL) {\r
618         continue;\r
619       }\r
620 \r
621       RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]);\r
622       RtPtrTrack.EndPtr   = GetEndPointer   (VariableStoreList[StoreType]);\r
623       RtPtrTrack.Volatile = (BOOLEAN) (StoreType == VariableStoreTypeVolatile);\r
624 \r
625       Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, mVariableAuthFormat);\r
626       if (!EFI_ERROR (Status)) {\r
627         break;\r
628       }\r
629     }\r
630 \r
631     if (!EFI_ERROR (Status)) {\r
632       //\r
633       // Get data size\r
634       //\r
635       TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat);\r
636       ASSERT (TempDataSize != 0);\r
637 \r
638       if (*DataSize >= TempDataSize) {\r
639         if (Data == NULL) {\r
640           Status = EFI_INVALID_PARAMETER;\r
641           goto Done;\r
642         }\r
643 \r
644         CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize);\r
645         if (Attributes != NULL) {\r
646           *Attributes = RtPtrTrack.CurrPtr->Attributes;\r
647         }\r
648 \r
649         *DataSize = TempDataSize;\r
650 \r
651         UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo);\r
652 \r
653         Status = EFI_SUCCESS;\r
654         goto Done;\r
655       } else {\r
656         *DataSize = TempDataSize;\r
657         Status = EFI_BUFFER_TOO_SMALL;\r
658         goto Done;\r
659       }\r
660     }\r
661   }\r
662 \r
663 Done:\r
664   mVariableRuntimeCacheReadLock = FALSE;\r
665 \r
666   return Status;\r
667 }\r
668 \r
669 /**\r
670   Finds the given variable in a variable store in SMM.\r
671 \r
672   Caution: This function may receive untrusted input.\r
673   The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
674 \r
675   @param[in]      VariableName       Name of Variable to be found.\r
676   @param[in]      VendorGuid         Variable vendor GUID.\r
677   @param[out]     Attributes         Attribute value of the variable found.\r
678   @param[in, out] DataSize           Size of Data found. If size is less than the\r
679                                      data, this value contains the required size.\r
680   @param[out]     Data               Data pointer.\r
681 \r
682   @retval EFI_SUCCESS                Found the specified variable.\r
683   @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
684   @retval EFI_NOT_FOUND              The specified variable could not be found.\r
685 \r
686 **/\r
687 EFI_STATUS\r
688 FindVariableInSmm (\r
689   IN      CHAR16                            *VariableName,\r
690   IN      EFI_GUID                          *VendorGuid,\r
691   OUT     UINT32                            *Attributes OPTIONAL,\r
692   IN OUT  UINTN                             *DataSize,\r
693   OUT     VOID                              *Data OPTIONAL\r
694   )\r
695 {\r
696   EFI_STATUS                                Status;\r
697   UINTN                                     PayloadSize;\r
698   SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;\r
699   UINTN                                     TempDataSize;\r
700   UINTN                                     VariableNameSize;\r
701 \r
702   if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
703     return EFI_INVALID_PARAMETER;\r
704   }\r
705 \r
706   TempDataSize          = *DataSize;\r
707   VariableNameSize      = StrSize (VariableName);\r
708   SmmVariableHeader     = NULL;\r
709 \r
710   //\r
711   // If VariableName exceeds SMM payload limit. Return failure\r
712   //\r
713   if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
714     return EFI_INVALID_PARAMETER;\r
715   }\r
716 \r
717   //\r
718   // Init the communicate buffer. The buffer data size is:\r
719   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
720   //\r
721   if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {\r
722     //\r
723     // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
724     //\r
725     TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;\r
726   }\r
727   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
728 \r
729   Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
730   if (EFI_ERROR (Status)) {\r
731     goto Done;\r
732   }\r
733   ASSERT (SmmVariableHeader != NULL);\r
734 \r
735   CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
736   SmmVariableHeader->DataSize   = TempDataSize;\r
737   SmmVariableHeader->NameSize   = VariableNameSize;\r
738   if (Attributes == NULL) {\r
739     SmmVariableHeader->Attributes = 0;\r
740   } else {\r
741     SmmVariableHeader->Attributes = *Attributes;\r
742   }\r
743   CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
744 \r
745   //\r
746   // Send data to SMM.\r
747   //\r
748   Status = SendCommunicateBuffer (PayloadSize);\r
749 \r
750   //\r
751   // Get data from SMM.\r
752   //\r
753   if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
754     //\r
755     // SMM CommBuffer DataSize can be a trimed value\r
756     // Only update DataSize when needed\r
757     //\r
758     *DataSize = SmmVariableHeader->DataSize;\r
759   }\r
760   if (Attributes != NULL) {\r
761     *Attributes = SmmVariableHeader->Attributes;\r
762   }\r
763 \r
764   if (EFI_ERROR (Status)) {\r
765     goto Done;\r
766   }\r
767 \r
768   if (Data != NULL) {\r
769     CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
770   } else {\r
771     Status = EFI_INVALID_PARAMETER;\r
772   }\r
773 \r
774 Done:\r
775   return Status;\r
776 }\r
777 \r
778 /**\r
779   This code finds variable in storage blocks (Volatile or Non-Volatile).\r
780 \r
781   Caution: This function may receive untrusted input.\r
782   The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
783 \r
784   @param[in]      VariableName       Name of Variable to be found.\r
785   @param[in]      VendorGuid         Variable vendor GUID.\r
786   @param[out]     Attributes         Attribute value of the variable found.\r
787   @param[in, out] DataSize           Size of Data found. If size is less than the\r
788                                      data, this value contains the required size.\r
789   @param[out]     Data               Data pointer.\r
790 \r
791   @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
792   @retval EFI_SUCCESS                Find the specified variable.\r
793   @retval EFI_NOT_FOUND              Not found.\r
794   @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
795 \r
796 **/\r
797 EFI_STATUS\r
798 EFIAPI\r
799 RuntimeServiceGetVariable (\r
800   IN      CHAR16                            *VariableName,\r
801   IN      EFI_GUID                          *VendorGuid,\r
802   OUT     UINT32                            *Attributes OPTIONAL,\r
803   IN OUT  UINTN                             *DataSize,\r
804   OUT     VOID                              *Data\r
805   )\r
806 {\r
807   EFI_STATUS                                Status;\r
808 \r
809   if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
810     return EFI_INVALID_PARAMETER;\r
811   }\r
812   if (VariableName[0] == 0) {\r
813     return EFI_NOT_FOUND;\r
814   }\r
815 \r
816   AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
817   if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
818     Status = FindVariableInRuntimeCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
819   } else {\r
820     Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, DataSize, Data);\r
821   }\r
822   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
823 \r
824   return Status;\r
825 }\r
826 \r
827 /**\r
828   Finds the next available variable in a runtime cache variable store.\r
829 \r
830   @param[in, out] VariableNameSize   Size of the variable name.\r
831   @param[in, out] VariableName       Pointer to variable name.\r
832   @param[in, out] VendorGuid         Variable Vendor Guid.\r
833 \r
834   @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
835   @retval EFI_SUCCESS                Find the specified variable.\r
836   @retval EFI_NOT_FOUND              Not found.\r
837   @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
838 \r
839 **/\r
840 EFI_STATUS\r
841 GetNextVariableNameInRuntimeCache (\r
842   IN OUT  UINTN                             *VariableNameSize,\r
843   IN OUT  CHAR16                            *VariableName,\r
844   IN OUT  EFI_GUID                          *VendorGuid\r
845   )\r
846 {\r
847   EFI_STATUS              Status;\r
848   UINTN                   VarNameSize;\r
849   VARIABLE_HEADER         *VariablePtr;\r
850   VARIABLE_STORE_HEADER   *VariableStoreHeader[VariableStoreTypeMax];\r
851 \r
852   Status = EFI_NOT_FOUND;\r
853 \r
854   //\r
855   // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service\r
856   // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent\r
857   // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime\r
858   // cache read lock should always be free when entering this function.\r
859   //\r
860   ASSERT (!mVariableRuntimeCacheReadLock);\r
861 \r
862   CheckForRuntimeCacheSync ();\r
863 \r
864   mVariableRuntimeCacheReadLock = TRUE;\r
865   if (!mVariableRuntimeCachePendingUpdate) {\r
866     //\r
867     // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
868     // The index and attributes mapping must be kept in this order as FindVariable\r
869     // makes use of this mapping to implement search algorithm.\r
870     //\r
871     VariableStoreHeader[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;\r
872     VariableStoreHeader[VariableStoreTypeHob]      = mVariableRuntimeHobCacheBuffer;\r
873     VariableStoreHeader[VariableStoreTypeNv]       = mVariableRuntimeNvCacheBuffer;\r
874 \r
875     Status =  VariableServiceGetNextVariableInternal (\r
876                 VariableName,\r
877                 VendorGuid,\r
878                 VariableStoreHeader,\r
879                 &VariablePtr,\r
880                 mVariableAuthFormat\r
881                 );\r
882     if (!EFI_ERROR (Status)) {\r
883       VarNameSize = NameSizeOfVariable (VariablePtr, mVariableAuthFormat);\r
884       ASSERT (VarNameSize != 0);\r
885       if (VarNameSize <= *VariableNameSize) {\r
886         CopyMem (VariableName, GetVariableNamePtr (VariablePtr, mVariableAuthFormat), VarNameSize);\r
887         CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr, mVariableAuthFormat), sizeof (EFI_GUID));\r
888         Status = EFI_SUCCESS;\r
889       } else {\r
890         Status = EFI_BUFFER_TOO_SMALL;\r
891       }\r
892 \r
893       *VariableNameSize = VarNameSize;\r
894     }\r
895   }\r
896   mVariableRuntimeCacheReadLock = FALSE;\r
897 \r
898   return Status;\r
899 }\r
900 \r
901 /**\r
902   Finds the next available variable in a SMM variable store.\r
903 \r
904   @param[in, out] VariableNameSize   Size of the variable name.\r
905   @param[in, out] VariableName       Pointer to variable name.\r
906   @param[in, out] VendorGuid         Variable Vendor Guid.\r
907 \r
908   @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
909   @retval EFI_SUCCESS                Find the specified variable.\r
910   @retval EFI_NOT_FOUND              Not found.\r
911   @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
912 \r
913 **/\r
914 EFI_STATUS\r
915 GetNextVariableNameInSmm (\r
916   IN OUT  UINTN                             *VariableNameSize,\r
917   IN OUT  CHAR16                            *VariableName,\r
918   IN OUT  EFI_GUID                          *VendorGuid\r
919   )\r
920 {\r
921   EFI_STATUS                                      Status;\r
922   UINTN                                           PayloadSize;\r
923   SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
924   UINTN                                           OutVariableNameSize;\r
925   UINTN                                           InVariableNameSize;\r
926 \r
927   OutVariableNameSize   = *VariableNameSize;\r
928   InVariableNameSize    = StrSize (VariableName);\r
929   SmmGetNextVariableName = NULL;\r
930 \r
931   //\r
932   // If input string exceeds SMM payload limit. Return failure\r
933   //\r
934   if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
935     return EFI_INVALID_PARAMETER;\r
936   }\r
937 \r
938   //\r
939   // Init the communicate buffer. The buffer data size is:\r
940   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
941   //\r
942   if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
943     //\r
944     // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
945     //\r
946     OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
947   }\r
948   //\r
949   // Payload should be Guid + NameSize + MAX of Input & Output buffer\r
950   //\r
951   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);\r
952 \r
953   Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
954   if (EFI_ERROR (Status)) {\r
955     goto Done;\r
956   }\r
957   ASSERT (SmmGetNextVariableName != NULL);\r
958 \r
959   //\r
960   // SMM comm buffer->NameSize is buffer size for return string\r
961   //\r
962   SmmGetNextVariableName->NameSize = OutVariableNameSize;\r
963 \r
964   CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
965   //\r
966   // Copy whole string\r
967   //\r
968   CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);\r
969   if (OutVariableNameSize > InVariableNameSize) {\r
970     ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
971   }\r
972 \r
973   //\r
974   // Send data to SMM\r
975   //\r
976   Status = SendCommunicateBuffer (PayloadSize);\r
977 \r
978   //\r
979   // Get data from SMM.\r
980   //\r
981   if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
982     //\r
983     // SMM CommBuffer NameSize can be a trimed value\r
984     // Only update VariableNameSize when needed\r
985     //\r
986     *VariableNameSize = SmmGetNextVariableName->NameSize;\r
987   }\r
988   if (EFI_ERROR (Status)) {\r
989     goto Done;\r
990   }\r
991 \r
992   CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
993   CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);\r
994 \r
995 Done:\r
996   return Status;\r
997 }\r
998 \r
999 /**\r
1000   This code Finds the Next available variable.\r
1001 \r
1002   @param[in, out] VariableNameSize   Size of the variable name.\r
1003   @param[in, out] VariableName       Pointer to variable name.\r
1004   @param[in, out] VendorGuid         Variable Vendor Guid.\r
1005 \r
1006   @retval EFI_INVALID_PARAMETER      Invalid parameter.\r
1007   @retval EFI_SUCCESS                Find the specified variable.\r
1008   @retval EFI_NOT_FOUND              Not found.\r
1009   @retval EFI_BUFFER_TO_SMALL        DataSize is too small for the result.\r
1010 \r
1011 **/\r
1012 EFI_STATUS\r
1013 EFIAPI\r
1014 RuntimeServiceGetNextVariableName (\r
1015   IN OUT  UINTN                             *VariableNameSize,\r
1016   IN OUT  CHAR16                            *VariableName,\r
1017   IN OUT  EFI_GUID                          *VendorGuid\r
1018   )\r
1019 {\r
1020   EFI_STATUS              Status;\r
1021   UINTN                   MaxLen;\r
1022 \r
1023   Status = EFI_NOT_FOUND;\r
1024 \r
1025   if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
1026     return EFI_INVALID_PARAMETER;\r
1027   }\r
1028 \r
1029   //\r
1030   // Calculate the possible maximum length of name string, including the Null terminator.\r
1031   //\r
1032   MaxLen = *VariableNameSize / sizeof (CHAR16);\r
1033   if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {\r
1034     //\r
1035     // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,\r
1036     // follow spec to return EFI_INVALID_PARAMETER.\r
1037     //\r
1038     return EFI_INVALID_PARAMETER;\r
1039   }\r
1040 \r
1041   AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
1042   if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
1043     Status = GetNextVariableNameInRuntimeCache (VariableNameSize, VariableName, VendorGuid);\r
1044   } else {\r
1045     Status = GetNextVariableNameInSmm (VariableNameSize, VariableName, VendorGuid);\r
1046   }\r
1047   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
1048 \r
1049   return Status;\r
1050 }\r
1051 \r
1052 /**\r
1053   This code sets variable in storage blocks (Volatile or Non-Volatile).\r
1054 \r
1055   Caution: This function may receive untrusted input.\r
1056   The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.\r
1057 \r
1058   @param[in] VariableName                 Name of Variable to be found.\r
1059   @param[in] VendorGuid                   Variable vendor GUID.\r
1060   @param[in] Attributes                   Attribute value of the variable found\r
1061   @param[in] DataSize                     Size of Data found. If size is less than the\r
1062                                           data, this value contains the required size.\r
1063   @param[in] Data                         Data pointer.\r
1064 \r
1065   @retval EFI_INVALID_PARAMETER           Invalid parameter.\r
1066   @retval EFI_SUCCESS                     Set successfully.\r
1067   @retval EFI_OUT_OF_RESOURCES            Resource not enough to set variable.\r
1068   @retval EFI_NOT_FOUND                   Not found.\r
1069   @retval EFI_WRITE_PROTECTED             Variable is read-only.\r
1070 \r
1071 **/\r
1072 EFI_STATUS\r
1073 EFIAPI\r
1074 RuntimeServiceSetVariable (\r
1075   IN CHAR16                                 *VariableName,\r
1076   IN EFI_GUID                               *VendorGuid,\r
1077   IN UINT32                                 Attributes,\r
1078   IN UINTN                                  DataSize,\r
1079   IN VOID                                   *Data\r
1080   )\r
1081 {\r
1082   EFI_STATUS                                Status;\r
1083   UINTN                                     PayloadSize;\r
1084   SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE  *SmmVariableHeader;\r
1085   UINTN                                     VariableNameSize;\r
1086 \r
1087   //\r
1088   // Check input parameters.\r
1089   //\r
1090   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
1091     return EFI_INVALID_PARAMETER;\r
1092   }\r
1093 \r
1094   if (DataSize != 0 && Data == NULL) {\r
1095     return EFI_INVALID_PARAMETER;\r
1096   }\r
1097 \r
1098   VariableNameSize      = StrSize (VariableName);\r
1099   SmmVariableHeader     = NULL;\r
1100 \r
1101   //\r
1102   // If VariableName or DataSize exceeds SMM payload limit. Return failure\r
1103   //\r
1104   if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
1105       (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){\r
1106     return EFI_INVALID_PARAMETER;\r
1107   }\r
1108 \r
1109   AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
1110 \r
1111   //\r
1112   // Init the communicate buffer. The buffer data size is:\r
1113   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
1114   //\r
1115   PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;\r
1116   Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
1117   if (EFI_ERROR (Status)) {\r
1118     goto Done;\r
1119   }\r
1120   ASSERT (SmmVariableHeader != NULL);\r
1121 \r
1122   CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
1123   SmmVariableHeader->DataSize   = DataSize;\r
1124   SmmVariableHeader->NameSize   = VariableNameSize;\r
1125   SmmVariableHeader->Attributes = Attributes;\r
1126   CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
1127   CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
1128 \r
1129   //\r
1130   // Send data to SMM.\r
1131   //\r
1132   Status = SendCommunicateBuffer (PayloadSize);\r
1133 \r
1134 Done:\r
1135   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
1136 \r
1137   if (!EfiAtRuntime ()) {\r
1138     if (!EFI_ERROR (Status)) {\r
1139       SecureBootHook (\r
1140         VariableName,\r
1141         VendorGuid\r
1142         );\r
1143     }\r
1144   }\r
1145   return Status;\r
1146 }\r
1147 \r
1148 \r
1149 /**\r
1150   This code returns information about the EFI variables.\r
1151 \r
1152   @param[in]  Attributes                   Attributes bitmask to specify the type of variables\r
1153                                            on which to return information.\r
1154   @param[out] MaximumVariableStorageSize   Pointer to the maximum size of the storage space available\r
1155                                            for the EFI variables associated with the attributes specified.\r
1156   @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
1157                                            for EFI variables associated with the attributes specified.\r
1158   @param[out] MaximumVariableSize          Pointer to the maximum size of an individual EFI variables\r
1159                                            associated with the attributes specified.\r
1160 \r
1161   @retval EFI_INVALID_PARAMETER            An invalid combination of attribute bits was supplied.\r
1162   @retval EFI_SUCCESS                      Query successfully.\r
1163   @retval EFI_UNSUPPORTED                  The attribute is not supported on this platform.\r
1164 \r
1165 **/\r
1166 EFI_STATUS\r
1167 EFIAPI\r
1168 RuntimeServiceQueryVariableInfo (\r
1169   IN  UINT32                                Attributes,\r
1170   OUT UINT64                                *MaximumVariableStorageSize,\r
1171   OUT UINT64                                *RemainingVariableStorageSize,\r
1172   OUT UINT64                                *MaximumVariableSize\r
1173   )\r
1174 {\r
1175   EFI_STATUS                                Status;\r
1176   UINTN                                     PayloadSize;\r
1177   SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
1178 \r
1179   SmmQueryVariableInfo = NULL;\r
1180 \r
1181   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
1182     return EFI_INVALID_PARAMETER;\r
1183   }\r
1184 \r
1185   AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
1186 \r
1187   //\r
1188   // Init the communicate buffer. The buffer data size is:\r
1189   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
1190   //\r
1191   PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
1192   Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
1193   if (EFI_ERROR (Status)) {\r
1194     goto Done;\r
1195   }\r
1196   ASSERT (SmmQueryVariableInfo != NULL);\r
1197 \r
1198   SmmQueryVariableInfo->Attributes  = Attributes;\r
1199 \r
1200   //\r
1201   // Send data to SMM.\r
1202   //\r
1203   Status = SendCommunicateBuffer (PayloadSize);\r
1204   if (EFI_ERROR (Status)) {\r
1205     goto Done;\r
1206   }\r
1207 \r
1208   //\r
1209   // Get data from SMM.\r
1210   //\r
1211   *MaximumVariableSize          = SmmQueryVariableInfo->MaximumVariableSize;\r
1212   *MaximumVariableStorageSize   = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
1213   *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;\r
1214 \r
1215 Done:\r
1216   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
1217   return Status;\r
1218 }\r
1219 \r
1220 \r
1221 /**\r
1222   Exit Boot Services Event notification handler.\r
1223 \r
1224   Notify SMM variable driver about the event.\r
1225 \r
1226   @param[in]  Event     Event whose notification function is being invoked.\r
1227   @param[in]  Context   Pointer to the notification function's context.\r
1228 \r
1229 **/\r
1230 VOID\r
1231 EFIAPI\r
1232 OnExitBootServices (\r
1233   IN      EFI_EVENT                         Event,\r
1234   IN      VOID                              *Context\r
1235   )\r
1236 {\r
1237   //\r
1238   // Init the communicate buffer. The buffer data size is:\r
1239   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
1240   //\r
1241   InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);\r
1242 \r
1243   //\r
1244   // Send data to SMM.\r
1245   //\r
1246   SendCommunicateBuffer (0);\r
1247 }\r
1248 \r
1249 \r
1250 /**\r
1251   On Ready To Boot Services Event notification handler.\r
1252 \r
1253   Notify SMM variable driver about the event.\r
1254 \r
1255   @param[in]  Event     Event whose notification function is being invoked\r
1256   @param[in]  Context   Pointer to the notification function's context\r
1257 \r
1258 **/\r
1259 VOID\r
1260 EFIAPI\r
1261 OnReadyToBoot (\r
1262   IN      EFI_EVENT                         Event,\r
1263   IN      VOID                              *Context\r
1264   )\r
1265 {\r
1266   //\r
1267   // Init the communicate buffer. The buffer data size is:\r
1268   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
1269   //\r
1270   InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
1271 \r
1272   //\r
1273   // Send data to SMM.\r
1274   //\r
1275   SendCommunicateBuffer (0);\r
1276 \r
1277   //\r
1278   // Install the system configuration table for variable info data captured\r
1279   //\r
1280   if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet (PcdVariableCollectStatistics)) {\r
1281     if (mVariableAuthFormat) {\r
1282       gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, mVariableInfo);\r
1283     } else {\r
1284       gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo);\r
1285     }\r
1286   }\r
1287 \r
1288   gBS->CloseEvent (Event);\r
1289 }\r
1290 \r
1291 \r
1292 /**\r
1293   Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
1294 \r
1295   This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
1296   It convers pointer to new virtual address.\r
1297 \r
1298   @param[in]  Event        Event whose notification function is being invoked.\r
1299   @param[in]  Context      Pointer to the notification function's context.\r
1300 \r
1301 **/\r
1302 VOID\r
1303 EFIAPI\r
1304 VariableAddressChangeEvent (\r
1305   IN EFI_EVENT                              Event,\r
1306   IN VOID                                   *Context\r
1307   )\r
1308 {\r
1309   EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
1310   EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
1311   EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeHobCacheBuffer);\r
1312   EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeNvCacheBuffer);\r
1313   EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeVolatileCacheBuffer);\r
1314 }\r
1315 \r
1316 /**\r
1317   This code gets variable payload size.\r
1318 \r
1319   @param[out] VariablePayloadSize   Output pointer to variable payload size.\r
1320 \r
1321   @retval EFI_SUCCESS               Get successfully.\r
1322   @retval Others                    Get unsuccessfully.\r
1323 \r
1324 **/\r
1325 EFI_STATUS\r
1326 EFIAPI\r
1327 GetVariablePayloadSize (\r
1328   OUT UINTN                         *VariablePayloadSize\r
1329   )\r
1330 {\r
1331   EFI_STATUS                                Status;\r
1332   SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;\r
1333   EFI_SMM_COMMUNICATE_HEADER                *SmmCommunicateHeader;\r
1334   SMM_VARIABLE_COMMUNICATE_HEADER           *SmmVariableFunctionHeader;\r
1335   UINTN                                     CommSize;\r
1336   UINT8                                     *CommBuffer;\r
1337 \r
1338   SmmGetPayloadSize = NULL;\r
1339   CommBuffer = NULL;\r
1340 \r
1341   if(VariablePayloadSize == NULL) {\r
1342     return EFI_INVALID_PARAMETER;\r
1343   }\r
1344 \r
1345   AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
1346 \r
1347   //\r
1348   // Init the communicate buffer. The buffer data size is:\r
1349   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
1350   //\r
1351   CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
1352   CommBuffer = AllocateZeroPool (CommSize);\r
1353   if (CommBuffer == NULL) {\r
1354     Status = EFI_OUT_OF_RESOURCES;\r
1355     goto Done;\r
1356   }\r
1357 \r
1358   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
1359   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
1360   SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
1361 \r
1362   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
1363   SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;\r
1364   SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;\r
1365 \r
1366   //\r
1367   // Send data to SMM.\r
1368   //\r
1369   Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
1370   ASSERT_EFI_ERROR (Status);\r
1371 \r
1372   Status = SmmVariableFunctionHeader->ReturnStatus;\r
1373   if (EFI_ERROR (Status)) {\r
1374     goto Done;\r
1375   }\r
1376 \r
1377   //\r
1378   // Get data from SMM.\r
1379   //\r
1380   *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;\r
1381 \r
1382 Done:\r
1383   if (CommBuffer != NULL) {\r
1384     FreePool (CommBuffer);\r
1385   }\r
1386   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
1387   return Status;\r
1388 }\r
1389 \r
1390 /**\r
1391   This code gets information needed from SMM for runtime cache initialization.\r
1392 \r
1393   @param[out] TotalHobStorageSize         Output pointer for the total HOB storage size in bytes.\r
1394   @param[out] TotalNvStorageSize          Output pointer for the total non-volatile storage size in bytes.\r
1395   @param[out] TotalVolatileStorageSize    Output pointer for the total volatile storage size in bytes.\r
1396   @param[out] AuthenticatedVariableUsage  Output pointer that indicates if authenticated variables are to be used.\r
1397 \r
1398   @retval EFI_SUCCESS                     Retrieved the size successfully.\r
1399   @retval EFI_INVALID_PARAMETER           TotalNvStorageSize parameter is NULL.\r
1400   @retval EFI_OUT_OF_RESOURCES            The memory resources needed for a CommBuffer are not available.\r
1401   @retval Others                          Could not retrieve the size successfully.\r
1402 \r
1403 **/\r
1404 EFI_STATUS\r
1405 GetRuntimeCacheInfo (\r
1406   OUT UINTN                         *TotalHobStorageSize,\r
1407   OUT UINTN                         *TotalNvStorageSize,\r
1408   OUT UINTN                         *TotalVolatileStorageSize,\r
1409   OUT BOOLEAN                       *AuthenticatedVariableUsage\r
1410   )\r
1411 {\r
1412   EFI_STATUS                                          Status;\r
1413   SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO     *SmmGetRuntimeCacheInfo;\r
1414   EFI_SMM_COMMUNICATE_HEADER                          *SmmCommunicateHeader;\r
1415   SMM_VARIABLE_COMMUNICATE_HEADER                     *SmmVariableFunctionHeader;\r
1416   UINTN                                               CommSize;\r
1417   UINT8                                               *CommBuffer;\r
1418 \r
1419   SmmGetRuntimeCacheInfo = NULL;\r
1420   CommBuffer = mVariableBuffer;\r
1421 \r
1422   if (TotalHobStorageSize == NULL || TotalNvStorageSize == NULL || TotalVolatileStorageSize == NULL || AuthenticatedVariableUsage == NULL) {\r
1423     return EFI_INVALID_PARAMETER;\r
1424   }\r
1425 \r
1426   if (CommBuffer == NULL) {\r
1427     return EFI_OUT_OF_RESOURCES;\r
1428   }\r
1429 \r
1430   AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
1431 \r
1432   CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);\r
1433   ZeroMem (CommBuffer, CommSize);\r
1434 \r
1435   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
1436   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
1437   SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);\r
1438 \r
1439   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
1440   SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO;\r
1441   SmmGetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;\r
1442 \r
1443   //\r
1444   // Send data to SMM.\r
1445   //\r
1446   Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
1447   ASSERT_EFI_ERROR (Status);\r
1448   if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {\r
1449     Status = EFI_BAD_BUFFER_SIZE;\r
1450     goto Done;\r
1451   }\r
1452 \r
1453   Status = SmmVariableFunctionHeader->ReturnStatus;\r
1454   if (EFI_ERROR (Status)) {\r
1455     goto Done;\r
1456   }\r
1457 \r
1458   //\r
1459   // Get data from SMM.\r
1460   //\r
1461   *TotalHobStorageSize = SmmGetRuntimeCacheInfo->TotalHobStorageSize;\r
1462   *TotalNvStorageSize = SmmGetRuntimeCacheInfo->TotalNvStorageSize;\r
1463   *TotalVolatileStorageSize = SmmGetRuntimeCacheInfo->TotalVolatileStorageSize;\r
1464   *AuthenticatedVariableUsage = SmmGetRuntimeCacheInfo->AuthenticatedVariableUsage;\r
1465 \r
1466 Done:\r
1467   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
1468   return Status;\r
1469 }\r
1470 \r
1471 /**\r
1472   Sends the runtime variable cache context information to SMM.\r
1473 \r
1474   @retval EFI_SUCCESS               Retrieved the size successfully.\r
1475   @retval EFI_INVALID_PARAMETER     TotalNvStorageSize parameter is NULL.\r
1476   @retval EFI_OUT_OF_RESOURCES      The memory resources needed for a CommBuffer are not available.\r
1477   @retval Others                    Could not retrieve the size successfully.;\r
1478 \r
1479 **/\r
1480 EFI_STATUS\r
1481 SendRuntimeVariableCacheContextToSmm (\r
1482   VOID\r
1483   )\r
1484 {\r
1485   EFI_STATUS                                                Status;\r
1486   SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT   *SmmRuntimeVarCacheContext;\r
1487   EFI_SMM_COMMUNICATE_HEADER                                *SmmCommunicateHeader;\r
1488   SMM_VARIABLE_COMMUNICATE_HEADER                           *SmmVariableFunctionHeader;\r
1489   UINTN                                                     CommSize;\r
1490   UINT8                                                     *CommBuffer;\r
1491 \r
1492   SmmRuntimeVarCacheContext = NULL;\r
1493   CommBuffer = mVariableBuffer;\r
1494 \r
1495   if (CommBuffer == NULL) {\r
1496     return EFI_OUT_OF_RESOURCES;\r
1497   }\r
1498 \r
1499   AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
1500 \r
1501   //\r
1502   // Init the communicate buffer. The buffer data size is:\r
1503   // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
1504   //\r
1505   CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
1506   ZeroMem (CommBuffer, CommSize);\r
1507 \r
1508   SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
1509   CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
1510   SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
1511 \r
1512   SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
1513   SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT;\r
1514   SmmRuntimeVarCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) SmmVariableFunctionHeader->Data;\r
1515 \r
1516   SmmRuntimeVarCacheContext->RuntimeHobCache = mVariableRuntimeHobCacheBuffer;\r
1517   SmmRuntimeVarCacheContext->RuntimeVolatileCache = mVariableRuntimeVolatileCacheBuffer;\r
1518   SmmRuntimeVarCacheContext->RuntimeNvCache = mVariableRuntimeNvCacheBuffer;\r
1519   SmmRuntimeVarCacheContext->PendingUpdate = &mVariableRuntimeCachePendingUpdate;\r
1520   SmmRuntimeVarCacheContext->ReadLock = &mVariableRuntimeCacheReadLock;\r
1521   SmmRuntimeVarCacheContext->HobFlushComplete = &mHobFlushComplete;\r
1522 \r
1523   //\r
1524   // Send data to SMM.\r
1525   //\r
1526   Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
1527   ASSERT_EFI_ERROR (Status);\r
1528   if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {\r
1529     Status = EFI_BAD_BUFFER_SIZE;\r
1530     goto Done;\r
1531   }\r
1532 \r
1533   Status = SmmVariableFunctionHeader->ReturnStatus;\r
1534   if (EFI_ERROR (Status)) {\r
1535     goto Done;\r
1536   }\r
1537 \r
1538 Done:\r
1539   ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
1540   return Status;\r
1541 }\r
1542 \r
1543 /**\r
1544   Initialize variable service and install Variable Architectural protocol.\r
1545 \r
1546   @param[in] Event    Event whose notification function is being invoked.\r
1547   @param[in] Context  Pointer to the notification function's context.\r
1548 \r
1549 **/\r
1550 VOID\r
1551 EFIAPI\r
1552 SmmVariableReady (\r
1553   IN  EFI_EVENT                             Event,\r
1554   IN  VOID                                  *Context\r
1555   )\r
1556 {\r
1557   EFI_STATUS                                Status;\r
1558 \r
1559   Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable);\r
1560   if (EFI_ERROR (Status)) {\r
1561     return;\r
1562   }\r
1563 \r
1564   Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
1565   ASSERT_EFI_ERROR (Status);\r
1566 \r
1567   //\r
1568   // Allocate memory for variable communicate buffer.\r
1569   //\r
1570   Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);\r
1571   ASSERT_EFI_ERROR (Status);\r
1572   mVariableBufferSize  = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
1573   mVariableBuffer      = AllocateRuntimePool (mVariableBufferSize);\r
1574   ASSERT (mVariableBuffer != NULL);\r
1575 \r
1576   //\r
1577   // Save the buffer physical address used for SMM conmunication.\r
1578   //\r
1579   mVariableBufferPhysical = mVariableBuffer;\r
1580 \r
1581   if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
1582     DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n"));\r
1583     //\r
1584     // Allocate runtime variable cache memory buffers.\r
1585     //\r
1586     Status =  GetRuntimeCacheInfo (\r
1587                 &mVariableRuntimeHobCacheBufferSize,\r
1588                 &mVariableRuntimeNvCacheBufferSize,\r
1589                 &mVariableRuntimeVolatileCacheBufferSize,\r
1590                 &mVariableAuthFormat\r
1591                 );\r
1592     if (!EFI_ERROR (Status)) {\r
1593       Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, &mVariableRuntimeHobCacheBufferSize);\r
1594       if (!EFI_ERROR (Status)) {\r
1595         Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, &mVariableRuntimeNvCacheBufferSize);\r
1596         if (!EFI_ERROR (Status)) {\r
1597           Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, &mVariableRuntimeVolatileCacheBufferSize);\r
1598           if (!EFI_ERROR (Status)) {\r
1599             Status = SendRuntimeVariableCacheContextToSmm ();\r
1600             if (!EFI_ERROR (Status)) {\r
1601               SyncRuntimeCache ();\r
1602             }\r
1603           }\r
1604         }\r
1605       }\r
1606       if (EFI_ERROR (Status)) {\r
1607         mVariableRuntimeHobCacheBuffer = NULL;\r
1608         mVariableRuntimeNvCacheBuffer = NULL;\r
1609         mVariableRuntimeVolatileCacheBuffer = NULL;\r
1610       }\r
1611     }\r
1612     ASSERT_EFI_ERROR (Status);\r
1613   } else {\r
1614     DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"));\r
1615   }\r
1616 \r
1617   gRT->GetVariable         = RuntimeServiceGetVariable;\r
1618   gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
1619   gRT->SetVariable         = RuntimeServiceSetVariable;\r
1620   gRT->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;\r
1621 \r
1622   //\r
1623   // Install the Variable Architectural Protocol on a new handle.\r
1624   //\r
1625   Status = gBS->InstallProtocolInterface (\r
1626                   &mHandle,\r
1627                   &gEfiVariableArchProtocolGuid,\r
1628                   EFI_NATIVE_INTERFACE,\r
1629                   NULL\r
1630                   );\r
1631   ASSERT_EFI_ERROR (Status);\r
1632 \r
1633   mVariableLock.RequestToLock = VariableLockRequestToLock;\r
1634   Status = gBS->InstallMultipleProtocolInterfaces (\r
1635                   &mHandle,\r
1636                   &gEdkiiVariableLockProtocolGuid,\r
1637                   &mVariableLock,\r
1638                   NULL\r
1639                   );\r
1640   ASSERT_EFI_ERROR (Status);\r
1641 \r
1642   mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;\r
1643   mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;\r
1644   mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;\r
1645   Status = gBS->InstallMultipleProtocolInterfaces (\r
1646                   &mHandle,\r
1647                   &gEdkiiVarCheckProtocolGuid,\r
1648                   &mVarCheck,\r
1649                   NULL\r
1650                   );\r
1651   ASSERT_EFI_ERROR (Status);\r
1652 \r
1653   gBS->CloseEvent (Event);\r
1654 }\r
1655 \r
1656 \r
1657 /**\r
1658   SMM Non-Volatile variable write service is ready notify event handler.\r
1659 \r
1660   @param[in] Event    Event whose notification function is being invoked.\r
1661   @param[in] Context  Pointer to the notification function's context.\r
1662 \r
1663 **/\r
1664 VOID\r
1665 EFIAPI\r
1666 SmmVariableWriteReady (\r
1667   IN  EFI_EVENT                             Event,\r
1668   IN  VOID                                  *Context\r
1669   )\r
1670 {\r
1671   EFI_STATUS                                Status;\r
1672   VOID                                      *ProtocolOps;\r
1673 \r
1674   //\r
1675   // Check whether the protocol is installed or not.\r
1676   //\r
1677   Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
1678   if (EFI_ERROR (Status)) {\r
1679     return;\r
1680   }\r
1681 \r
1682   //\r
1683   // Some Secure Boot Policy Var (SecureBoot, etc) updates following other\r
1684   // Secure Boot Policy Variable change.  Record their initial value.\r
1685   //\r
1686   RecordSecureBootPolicyVarData();\r
1687 \r
1688   Status = gBS->InstallProtocolInterface (\r
1689                   &mHandle,\r
1690                   &gEfiVariableWriteArchProtocolGuid,\r
1691                   EFI_NATIVE_INTERFACE,\r
1692                   NULL\r
1693                   );\r
1694   ASSERT_EFI_ERROR (Status);\r
1695 \r
1696   gBS->CloseEvent (Event);\r
1697 }\r
1698 \r
1699 \r
1700 /**\r
1701   Variable Driver main entry point. The Variable driver places the 4 EFI\r
1702   runtime services in the EFI System Table and installs arch protocols\r
1703   for variable read and write services being available. It also registers\r
1704   a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
1705 \r
1706   @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
1707   @param[in] SystemTable    A pointer to the EFI System Table.\r
1708 \r
1709   @retval EFI_SUCCESS       Variable service successfully initialized.\r
1710 \r
1711 **/\r
1712 EFI_STATUS\r
1713 EFIAPI\r
1714 VariableSmmRuntimeInitialize (\r
1715   IN EFI_HANDLE                             ImageHandle,\r
1716   IN EFI_SYSTEM_TABLE                       *SystemTable\r
1717   )\r
1718 {\r
1719   VOID                                      *SmmVariableRegistration;\r
1720   VOID                                      *SmmVariableWriteRegistration;\r
1721   EFI_EVENT                                 OnReadyToBootEvent;\r
1722   EFI_EVENT                                 ExitBootServiceEvent;\r
1723   EFI_EVENT                                 LegacyBootEvent;\r
1724 \r
1725   EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\r
1726 \r
1727   //\r
1728   // Smm variable service is ready\r
1729   //\r
1730   EfiCreateProtocolNotifyEvent (\r
1731     &gEfiSmmVariableProtocolGuid,\r
1732     TPL_CALLBACK,\r
1733     SmmVariableReady,\r
1734     NULL,\r
1735     &SmmVariableRegistration\r
1736     );\r
1737 \r
1738   //\r
1739   // Smm Non-Volatile variable write service is ready\r
1740   //\r
1741   EfiCreateProtocolNotifyEvent (\r
1742     &gSmmVariableWriteGuid,\r
1743     TPL_CALLBACK,\r
1744     SmmVariableWriteReady,\r
1745     NULL,\r
1746     &SmmVariableWriteRegistration\r
1747     );\r
1748 \r
1749   //\r
1750   // Register the event to reclaim variable for OS usage.\r
1751   //\r
1752   EfiCreateEventReadyToBootEx (\r
1753     TPL_NOTIFY,\r
1754     OnReadyToBoot,\r
1755     NULL,\r
1756     &OnReadyToBootEvent\r
1757     );\r
1758 \r
1759   //\r
1760   // Register the event to inform SMM variable that it is at runtime.\r
1761   //\r
1762   gBS->CreateEventEx (\r
1763          EVT_NOTIFY_SIGNAL,\r
1764          TPL_NOTIFY,\r
1765          OnExitBootServices,\r
1766          NULL,\r
1767          &gEfiEventExitBootServicesGuid,\r
1768          &ExitBootServiceEvent\r
1769          );\r
1770 \r
1771   //\r
1772   // Register the event to inform SMM variable that it is at runtime for legacy boot.\r
1773   // Reuse OnExitBootServices() here.\r
1774   //\r
1775   EfiCreateEventLegacyBootEx(\r
1776     TPL_NOTIFY,\r
1777     OnExitBootServices,\r
1778     NULL,\r
1779     &LegacyBootEvent\r
1780     );\r
1781 \r
1782   //\r
1783   // Register the event to convert the pointer for runtime.\r
1784   //\r
1785   gBS->CreateEventEx (\r
1786          EVT_NOTIFY_SIGNAL,\r
1787          TPL_NOTIFY,\r
1788          VariableAddressChangeEvent,\r
1789          NULL,\r
1790          &gEfiEventVirtualAddressChangeGuid,\r
1791          &mVirtualAddressChangeEvent\r
1792          );\r
1793 \r
1794   return EFI_SUCCESS;\r
1795 }\r
1796 \r