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