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