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