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