]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.c
MdeModulePkg: Connect VariablePolicy business logic to VariableServices
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmm.c
CommitLineData
8a2d4996 1/** @file\r
fa0737a8
SZ
2 The sample implementation for SMM variable protocol. And this driver\r
3 implements an SMI handler to communicate with the DXE runtime driver\r
8a2d4996 4 to provide variable services.\r
5\r
2445a70e 6 Caution: This module requires additional review when modified.\r
7 This driver will have external input - variable data and communicate buffer in SMM mode.\r
8 This external input must be validated carefully to avoid security issue like\r
9 buffer overflow, integer overflow.\r
10\r
11 SmmVariableHandler() will receive untrusted input and do basic validation.\r
12\r
fa0737a8
SZ
13 Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),\r
14 VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),\r
2445a70e 15 SmmVariableGetStatistics() should also do validation based on its own knowledge.\r
16\r
904e0ca9 17Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>\r
a855f63e 18Copyright (c) 2018, Linaro, Ltd. All rights reserved.<BR>\r
9d510e61 19SPDX-License-Identifier: BSD-2-Clause-Patent\r
8a2d4996 20\r
21**/\r
fa0737a8 22\r
d00ed85e 23#include <Protocol/SmmVariable.h>\r
24#include <Protocol/SmmFirmwareVolumeBlock.h>\r
8a2d4996 25#include <Protocol/SmmFaultTolerantWrite.h>\r
a855f63e 26#include <Protocol/MmEndOfDxe.h>\r
efb01a10 27#include <Protocol/SmmVarCheck.h>\r
2445a70e 28\r
a855f63e 29#include <Library/MmServicesTableLib.h>\r
b6490426 30#include <Library/VariablePolicyLib.h>\r
8a2d4996 31\r
d00ed85e 32#include <Guid/SmmVariableCommon.h>\r
8a2d4996 33#include "Variable.h"\r
20a27a64 34#include "VariableParsing.h"\r
aab3b9b9
MK
35#include "VariableRuntimeCache.h"\r
36\r
37extern VARIABLE_STORE_HEADER *mNvVariableCache;\r
8a2d4996 38\r
8a2d4996 39BOOLEAN mAtRuntime = FALSE;\r
5e5bb2a9
SZ
40UINT8 *mVariableBufferPayload = NULL;\r
41UINTN mVariableBufferPayloadSize;\r
ff843847 42\r
fa0737a8
SZ
43/**\r
44 SecureBoot Hook for SetVariable.\r
45\r
46 @param[in] VariableName Name of Variable to be found.\r
47 @param[in] VendorGuid Variable vendor GUID.\r
48\r
49**/\r
50VOID\r
51EFIAPI\r
52SecureBootHook (\r
53 IN CHAR16 *VariableName,\r
54 IN EFI_GUID *VendorGuid\r
55 )\r
56{\r
57 return ;\r
58}\r
59\r
ff843847
RN
60/**\r
61\r
62 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
63\r
64 @param VariableName Name of Variable to be found.\r
65 @param VendorGuid Variable vendor GUID.\r
66 @param Attributes Attribute value of the variable found\r
67 @param DataSize Size of Data found. If size is less than the\r
68 data, this value contains the required size.\r
69 @param Data Data pointer.\r
70\r
71 @return EFI_INVALID_PARAMETER Invalid parameter.\r
72 @return EFI_SUCCESS Set successfully.\r
73 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
74 @return EFI_NOT_FOUND Not found.\r
75 @return EFI_WRITE_PROTECTED Variable is read-only.\r
76\r
77**/\r
78EFI_STATUS\r
79EFIAPI\r
80SmmVariableSetVariable (\r
81 IN CHAR16 *VariableName,\r
82 IN EFI_GUID *VendorGuid,\r
83 IN UINT32 Attributes,\r
84 IN UINTN DataSize,\r
85 IN VOID *Data\r
86 )\r
87{\r
88 EFI_STATUS Status;\r
89\r
90 //\r
91 // Disable write protection when the calling SetVariable() through EFI_SMM_VARIABLE_PROTOCOL.\r
92 //\r
8021f4c7 93 mRequestSource = VarCheckFromTrusted;\r
ff843847
RN
94 Status = VariableServiceSetVariable (\r
95 VariableName,\r
96 VendorGuid,\r
97 Attributes,\r
98 DataSize,\r
99 Data\r
100 );\r
8021f4c7 101 mRequestSource = VarCheckFromUntrusted;\r
ff843847
RN
102 return Status;\r
103}\r
5e5bb2a9 104\r
8a2d4996 105EFI_SMM_VARIABLE_PROTOCOL gSmmVariable = {\r
106 VariableServiceGetVariable,\r
107 VariableServiceGetNextVariableName,\r
ff843847 108 SmmVariableSetVariable,\r
8a2d4996 109 VariableServiceQueryVariableInfo\r
110};\r
111\r
efb01a10
SZ
112EDKII_SMM_VAR_CHECK_PROTOCOL mSmmVarCheck = { VarCheckRegisterSetVariableCheckHandler,\r
113 VarCheckVariablePropertySet,\r
114 VarCheckVariablePropertyGet };\r
115\r
8a2d4996 116/**\r
117 Return TRUE if ExitBootServices () has been called.\r
fa0737a8 118\r
8a2d4996 119 @retval TRUE If ExitBootServices () has been called.\r
120**/\r
121BOOLEAN\r
122AtRuntime (\r
123 VOID\r
124 )\r
125{\r
126 return mAtRuntime;\r
127}\r
128\r
129/**\r
130 Initializes a basic mutual exclusion lock.\r
131\r
fa0737a8
SZ
132 This function initializes a basic mutual exclusion lock to the released state\r
133 and returns the lock. Each lock provides mutual exclusion access at its task\r
8a2d4996 134 priority level. Since there is no preemption or multiprocessor support in EFI,\r
135 acquiring the lock only consists of raising to the locks TPL.\r
136 If Lock is NULL, then ASSERT().\r
137 If Priority is not a valid TPL value, then ASSERT().\r
138\r
139 @param Lock A pointer to the lock data structure to initialize.\r
140 @param Priority EFI TPL is associated with the lock.\r
141\r
142 @return The lock.\r
143\r
144**/\r
145EFI_LOCK *\r
146InitializeLock (\r
147 IN OUT EFI_LOCK *Lock,\r
148 IN EFI_TPL Priority\r
149 )\r
150{\r
151 return Lock;\r
152}\r
153\r
154/**\r
155 Acquires lock only at boot time. Simply returns at runtime.\r
156\r
157 This is a temperary function that will be removed when\r
158 EfiAcquireLock() in UefiLib can handle the call in UEFI\r
159 Runtimer driver in RT phase.\r
160 It calls EfiAcquireLock() at boot time, and simply returns\r
161 at runtime.\r
162\r
163 @param Lock A pointer to the lock to acquire.\r
164\r
165**/\r
166VOID\r
167AcquireLockOnlyAtBootTime (\r
168 IN EFI_LOCK *Lock\r
169 )\r
170{\r
171\r
172}\r
173\r
174\r
175/**\r
176 Releases lock only at boot time. Simply returns at runtime.\r
177\r
178 This is a temperary function which will be removed when\r
179 EfiReleaseLock() in UefiLib can handle the call in UEFI\r
180 Runtimer driver in RT phase.\r
181 It calls EfiReleaseLock() at boot time and simply returns\r
182 at runtime.\r
183\r
184 @param Lock A pointer to the lock to release.\r
185\r
186**/\r
187VOID\r
188ReleaseLockOnlyAtBootTime (\r
189 IN EFI_LOCK *Lock\r
190 )\r
191{\r
192\r
193}\r
194\r
195/**\r
0a18956d 196 Retrieve the SMM Fault Tolerent Write protocol interface.\r
8a2d4996 197\r
198 @param[out] FtwProtocol The interface of SMM Ftw protocol\r
199\r
200 @retval EFI_SUCCESS The SMM FTW protocol instance was found and returned in FtwProtocol.\r
201 @retval EFI_NOT_FOUND The SMM FTW protocol instance was not found.\r
202 @retval EFI_INVALID_PARAMETER SarProtocol is NULL.\r
203\r
204**/\r
205EFI_STATUS\r
206GetFtwProtocol (\r
207 OUT VOID **FtwProtocol\r
208 )\r
209{\r
210 EFI_STATUS Status;\r
211\r
212 //\r
213 // Locate Smm Fault Tolerent Write protocol\r
214 //\r
a855f63e 215 Status = gMmst->MmLocateProtocol (\r
fa0737a8
SZ
216 &gEfiSmmFaultTolerantWriteProtocolGuid,\r
217 NULL,\r
8a2d4996 218 FtwProtocol\r
219 );\r
220 return Status;\r
221}\r
222\r
223\r
224/**\r
0a18956d 225 Retrieve the SMM FVB protocol interface by HANDLE.\r
8a2d4996 226\r
227 @param[in] FvBlockHandle The handle of SMM FVB protocol that provides services for\r
228 reading, writing, and erasing the target block.\r
229 @param[out] FvBlock The interface of SMM FVB protocol\r
230\r
231 @retval EFI_SUCCESS The interface information for the specified protocol was returned.\r
232 @retval EFI_UNSUPPORTED The device does not support the SMM FVB protocol.\r
233 @retval EFI_INVALID_PARAMETER FvBlockHandle is not a valid EFI_HANDLE or FvBlock is NULL.\r
234\r
235**/\r
236EFI_STATUS\r
237GetFvbByHandle (\r
238 IN EFI_HANDLE FvBlockHandle,\r
239 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvBlock\r
240 )\r
241{\r
242 //\r
243 // To get the SMM FVB protocol interface on the handle\r
244 //\r
a855f63e 245 return gMmst->MmHandleProtocol (\r
8a2d4996 246 FvBlockHandle,\r
247 &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
248 (VOID **) FvBlock\r
249 );\r
250}\r
251\r
252\r
253/**\r
254 Function returns an array of handles that support the SMM FVB protocol\r
fa0737a8 255 in a buffer allocated from pool.\r
8a2d4996 256\r
257 @param[out] NumberHandles The number of handles returned in Buffer.\r
258 @param[out] Buffer A pointer to the buffer to return the requested\r
259 array of handles that support SMM FVB protocol.\r
260\r
261 @retval EFI_SUCCESS The array of handles was returned in Buffer, and the number of\r
262 handles in Buffer was returned in NumberHandles.\r
263 @retval EFI_NOT_FOUND No SMM FVB handle was found.\r
264 @retval EFI_OUT_OF_RESOURCES There is not enough pool memory to store the matching results.\r
265 @retval EFI_INVALID_PARAMETER NumberHandles is NULL or Buffer is NULL.\r
266\r
267**/\r
268EFI_STATUS\r
269GetFvbCountAndBuffer (\r
270 OUT UINTN *NumberHandles,\r
271 OUT EFI_HANDLE **Buffer\r
272 )\r
273{\r
274 EFI_STATUS Status;\r
275 UINTN BufferSize;\r
276\r
277 if ((NumberHandles == NULL) || (Buffer == NULL)) {\r
278 return EFI_INVALID_PARAMETER;\r
279 }\r
280\r
281 BufferSize = 0;\r
282 *NumberHandles = 0;\r
283 *Buffer = NULL;\r
a855f63e 284 Status = gMmst->MmLocateHandle (\r
8a2d4996 285 ByProtocol,\r
286 &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
287 NULL,\r
288 &BufferSize,\r
289 *Buffer\r
290 );\r
291 if (EFI_ERROR(Status) && Status != EFI_BUFFER_TOO_SMALL) {\r
292 return EFI_NOT_FOUND;\r
293 }\r
294\r
295 *Buffer = AllocatePool (BufferSize);\r
296 if (*Buffer == NULL) {\r
297 return EFI_OUT_OF_RESOURCES;\r
298 }\r
299\r
a855f63e 300 Status = gMmst->MmLocateHandle (\r
8a2d4996 301 ByProtocol,\r
302 &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
303 NULL,\r
304 &BufferSize,\r
305 *Buffer\r
306 );\r
307\r
308 *NumberHandles = BufferSize / sizeof(EFI_HANDLE);\r
309 if (EFI_ERROR(Status)) {\r
310 *NumberHandles = 0;\r
5e5bb2a9
SZ
311 FreePool (*Buffer);\r
312 *Buffer = NULL;\r
8a2d4996 313 }\r
314\r
315 return Status;\r
316}\r
317\r
318\r
319/**\r
320 Get the variable statistics information from the information buffer pointed by gVariableInfo.\r
321\r
2445a70e 322 Caution: This function may be invoked at SMM runtime.\r
323 InfoEntry and InfoSize are external input. Care must be taken to make sure not security issue at runtime.\r
324\r
325 @param[in, out] InfoEntry A pointer to the buffer of variable information entry.\r
fa0737a8 326 On input, point to the variable information returned last time. if\r
2445a70e 327 InfoEntry->VendorGuid is zero, return the first information.\r
328 On output, point to the next variable information.\r
329 @param[in, out] InfoSize On input, the size of the variable information buffer.\r
330 On output, the returned variable information size.\r
8a2d4996 331\r
fa0737a8
SZ
332 @retval EFI_SUCCESS The variable information is found and returned successfully.\r
333 @retval EFI_UNSUPPORTED No variable inoformation exists in variable driver. The\r
334 PcdVariableCollectStatistics should be set TRUE to support it.\r
335 @retval EFI_BUFFER_TOO_SMALL The buffer is too small to hold the next variable information.\r
336 @retval EFI_INVALID_PARAMETER Input parameter is invalid.\r
8a2d4996 337\r
338**/\r
339EFI_STATUS\r
340SmmVariableGetStatistics (\r
d00ed85e 341 IN OUT VARIABLE_INFO_ENTRY *InfoEntry,\r
8a2d4996 342 IN OUT UINTN *InfoSize\r
343 )\r
344{\r
d00ed85e 345 VARIABLE_INFO_ENTRY *VariableInfo;\r
d5aef955 346 UINTN NameSize;\r
8a2d4996 347 UINTN StatisticsInfoSize;\r
348 CHAR16 *InfoName;\r
d5aef955 349 UINTN InfoNameMaxSize;\r
5e5bb2a9
SZ
350 EFI_GUID VendorGuid;\r
351\r
fa0737a8
SZ
352 if (InfoEntry == NULL) {\r
353 return EFI_INVALID_PARAMETER;\r
354 }\r
355\r
356 VariableInfo = gVariableInfo;\r
8a2d4996 357 if (VariableInfo == NULL) {\r
358 return EFI_UNSUPPORTED;\r
359 }\r
360\r
d5aef955 361 StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY);\r
eb96e4f2 362 if (*InfoSize < StatisticsInfoSize) {\r
8a2d4996 363 *InfoSize = StatisticsInfoSize;\r
364 return EFI_BUFFER_TOO_SMALL;\r
365 }\r
366 InfoName = (CHAR16 *)(InfoEntry + 1);\r
d5aef955 367 InfoNameMaxSize = (*InfoSize - sizeof (VARIABLE_INFO_ENTRY));\r
8a2d4996 368\r
5e5bb2a9
SZ
369 CopyGuid (&VendorGuid, &InfoEntry->VendorGuid);\r
370\r
39cde03c 371 if (IsZeroGuid (&VendorGuid)) {\r
8a2d4996 372 //\r
373 // Return the first variable info\r
374 //\r
d5aef955
SZ
375 NameSize = StrSize (VariableInfo->Name);\r
376 StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + NameSize;\r
377 if (*InfoSize < StatisticsInfoSize) {\r
378 *InfoSize = StatisticsInfoSize;\r
379 return EFI_BUFFER_TOO_SMALL;\r
380 }\r
d00ed85e 381 CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));\r
d5aef955 382 CopyMem (InfoName, VariableInfo->Name, NameSize);\r
8a2d4996 383 *InfoSize = StatisticsInfoSize;\r
384 return EFI_SUCCESS;\r
385 }\r
386\r
387 //\r
388 // Get the next variable info\r
389 //\r
390 while (VariableInfo != NULL) {\r
5e5bb2a9 391 if (CompareGuid (&VariableInfo->VendorGuid, &VendorGuid)) {\r
d5aef955
SZ
392 NameSize = StrSize (VariableInfo->Name);\r
393 if (NameSize <= InfoNameMaxSize) {\r
394 if (CompareMem (VariableInfo->Name, InfoName, NameSize) == 0) {\r
8a2d4996 395 //\r
396 // Find the match one\r
397 //\r
398 VariableInfo = VariableInfo->Next;\r
399 break;\r
400 }\r
401 }\r
402 }\r
403 VariableInfo = VariableInfo->Next;\r
404 };\r
fa0737a8 405\r
8a2d4996 406 if (VariableInfo == NULL) {\r
407 *InfoSize = 0;\r
408 return EFI_SUCCESS;\r
409 }\r
410\r
411 //\r
412 // Output the new variable info\r
413 //\r
d5aef955
SZ
414 NameSize = StrSize (VariableInfo->Name);\r
415 StatisticsInfoSize = sizeof (VARIABLE_INFO_ENTRY) + NameSize;\r
8a2d4996 416 if (*InfoSize < StatisticsInfoSize) {\r
417 *InfoSize = StatisticsInfoSize;\r
418 return EFI_BUFFER_TOO_SMALL;\r
419 }\r
420\r
d00ed85e 421 CopyMem (InfoEntry, VariableInfo, sizeof (VARIABLE_INFO_ENTRY));\r
d5aef955 422 CopyMem (InfoName, VariableInfo->Name, NameSize);\r
8a2d4996 423 *InfoSize = StatisticsInfoSize;\r
fa0737a8 424\r
8a2d4996 425 return EFI_SUCCESS;\r
426}\r
427\r
428\r
429/**\r
430 Communication service SMI Handler entry.\r
431\r
432 This SMI handler provides services for the variable wrapper driver.\r
433\r
2445a70e 434 Caution: This function may receive untrusted input.\r
435 This variable data and communicate buffer are external input, so this function will do basic validation.\r
fa0737a8
SZ
436 Each sub function VariableServiceGetVariable(), VariableServiceGetNextVariableName(),\r
437 VariableServiceSetVariable(), VariableServiceQueryVariableInfo(), ReclaimForOS(),\r
2445a70e 438 SmmVariableGetStatistics() should also do validation based on its own knowledge.\r
439\r
8a2d4996 440 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
441 @param[in] RegisterContext Points to an optional handler context which was specified when the\r
442 handler was registered.\r
443 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
444 be conveyed from a non-SMM environment into an SMM environment.\r
445 @param[in, out] CommBufferSize The size of the CommBuffer.\r
446\r
fa0737a8 447 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers\r
8a2d4996 448 should still be called.\r
fa0737a8 449 @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has been quiesced but other handlers should\r
8a2d4996 450 still be called.\r
fa0737a8 451 @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still pending and other handlers should still\r
8a2d4996 452 be called.\r
453 @retval EFI_INTERRUPT_PENDING The interrupt could not be quiesced.\r
454**/\r
455EFI_STATUS\r
456EFIAPI\r
457SmmVariableHandler (\r
aab3b9b9
MK
458 IN EFI_HANDLE DispatchHandle,\r
459 IN CONST VOID *RegisterContext,\r
460 IN OUT VOID *CommBuffer,\r
461 IN OUT UINTN *CommBufferSize\r
8a2d4996 462 )\r
463{\r
aab3b9b9
MK
464 EFI_STATUS Status;\r
465 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
466 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
467 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *GetNextVariableName;\r
468 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *QueryVariableInfo;\r
469 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *GetPayloadSize;\r
470 SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *RuntimeVariableCacheContext;\r
471 SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *GetRuntimeCacheInfo;\r
472 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;\r
473 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
474 VARIABLE_INFO_ENTRY *VariableInfo;\r
475 VARIABLE_RUNTIME_CACHE_CONTEXT *VariableCacheContext;\r
476 VARIABLE_STORE_HEADER *VariableCache;\r
477 UINTN InfoSize;\r
478 UINTN NameBufferSize;\r
479 UINTN CommBufferPayloadSize;\r
480 UINTN TempCommBufferSize;\r
8a2d4996 481\r
2445a70e 482 //\r
483 // If input is invalid, stop processing this SMI\r
484 //\r
485 if (CommBuffer == NULL || CommBufferSize == NULL) {\r
486 return EFI_SUCCESS;\r
487 }\r
488\r
164a9b67
SZ
489 TempCommBufferSize = *CommBufferSize;\r
490\r
491 if (TempCommBufferSize < SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {\r
5e5bb2a9
SZ
492 DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer size invalid!\n"));\r
493 return EFI_SUCCESS;\r
494 }\r
164a9b67 495 CommBufferPayloadSize = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
5e5bb2a9
SZ
496 if (CommBufferPayloadSize > mVariableBufferPayloadSize) {\r
497 DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer payload size invalid!\n"));\r
2445a70e 498 return EFI_SUCCESS;\r
499 }\r
500\r
a855f63e 501 if (!VariableSmmIsBufferOutsideSmmValid ((UINTN)CommBuffer, TempCommBufferSize)) {\r
5e5bb2a9 502 DEBUG ((EFI_D_ERROR, "SmmVariableHandler: SMM communication buffer in SMRAM or overflow!\n"));\r
2445a70e 503 return EFI_SUCCESS;\r
504 }\r
8a2d4996 505\r
506 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)CommBuffer;\r
507 switch (SmmVariableFunctionHeader->Function) {\r
508 case SMM_VARIABLE_FUNCTION_GET_VARIABLE:\r
5e5bb2a9
SZ
509 if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
510 DEBUG ((EFI_D_ERROR, "GetVariable: SMM communication buffer size invalid!\n"));\r
511 return EFI_SUCCESS;\r
512 }\r
513 //\r
514 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.\r
515 //\r
516 CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);\r
517 SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;\r
9d00d20e
SZ
518 if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
519 ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {\r
520 //\r
521 // Prevent InfoSize overflow happen\r
522 //\r
523 Status = EFI_ACCESS_DENIED;\r
524 goto EXIT;\r
525 }\r
fa0737a8 526 InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)\r
2445a70e 527 + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;\r
528\r
529 //\r
530 // SMRAM range check already covered before\r
531 //\r
5e5bb2a9
SZ
532 if (InfoSize > CommBufferPayloadSize) {\r
533 DEBUG ((EFI_D_ERROR, "GetVariable: Data size exceed communication buffer size limit!\n"));\r
2445a70e 534 Status = EFI_ACCESS_DENIED;\r
535 goto EXIT;\r
536 }\r
537\r
e83d841f 538 //\r
49395ea0
HW
539 // The VariableSpeculationBarrier() call here is to ensure the previous\r
540 // range/content checks for the CommBuffer have been completed before the\r
541 // subsequent consumption of the CommBuffer content.\r
e83d841f 542 //\r
49395ea0 543 VariableSpeculationBarrier ();\r
9d00d20e
SZ
544 if (SmmVariableHeader->NameSize < sizeof (CHAR16) || SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - 1] != L'\0') {\r
545 //\r
546 // Make sure VariableName is A Null-terminated string.\r
547 //\r
548 Status = EFI_ACCESS_DENIED;\r
549 goto EXIT;\r
550 }\r
551\r
8a2d4996 552 Status = VariableServiceGetVariable (\r
553 SmmVariableHeader->Name,\r
554 &SmmVariableHeader->Guid,\r
555 &SmmVariableHeader->Attributes,\r
556 &SmmVariableHeader->DataSize,\r
557 (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize\r
558 );\r
5e5bb2a9 559 CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);\r
8a2d4996 560 break;\r
fa0737a8 561\r
8a2d4996 562 case SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME:\r
5e5bb2a9
SZ
563 if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
564 DEBUG ((EFI_D_ERROR, "GetNextVariableName: SMM communication buffer size invalid!\n"));\r
565 return EFI_SUCCESS;\r
566 }\r
567 //\r
568 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.\r
569 //\r
570 CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);\r
571 GetNextVariableName = (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *) mVariableBufferPayload;\r
9d00d20e
SZ
572 if ((UINTN)(~0) - GetNextVariableName->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
573 //\r
574 // Prevent InfoSize overflow happen\r
575 //\r
576 Status = EFI_ACCESS_DENIED;\r
577 goto EXIT;\r
578 }\r
2445a70e 579 InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + GetNextVariableName->NameSize;\r
580\r
581 //\r
582 // SMRAM range check already covered before\r
583 //\r
5e5bb2a9
SZ
584 if (InfoSize > CommBufferPayloadSize) {\r
585 DEBUG ((EFI_D_ERROR, "GetNextVariableName: Data size exceed communication buffer size limit!\n"));\r
2445a70e 586 Status = EFI_ACCESS_DENIED;\r
587 goto EXIT;\r
588 }\r
589\r
5e5bb2a9 590 NameBufferSize = CommBufferPayloadSize - OFFSET_OF(SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
9d00d20e
SZ
591 if (NameBufferSize < sizeof (CHAR16) || GetNextVariableName->Name[NameBufferSize/sizeof (CHAR16) - 1] != L'\0') {\r
592 //\r
593 // Make sure input VariableName is A Null-terminated string.\r
594 //\r
595 Status = EFI_ACCESS_DENIED;\r
596 goto EXIT;\r
597 }\r
598\r
8a2d4996 599 Status = VariableServiceGetNextVariableName (\r
600 &GetNextVariableName->NameSize,\r
601 GetNextVariableName->Name,\r
602 &GetNextVariableName->Guid\r
603 );\r
5e5bb2a9 604 CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);\r
8a2d4996 605 break;\r
fa0737a8 606\r
8a2d4996 607 case SMM_VARIABLE_FUNCTION_SET_VARIABLE:\r
5e5bb2a9
SZ
608 if (CommBufferPayloadSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
609 DEBUG ((EFI_D_ERROR, "SetVariable: SMM communication buffer size invalid!\n"));\r
610 return EFI_SUCCESS;\r
611 }\r
612 //\r
613 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.\r
614 //\r
615 CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);\r
616 SmmVariableHeader = (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *) mVariableBufferPayload;\r
9d00d20e
SZ
617 if (((UINTN)(~0) - SmmVariableHeader->DataSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
618 ((UINTN)(~0) - SmmVariableHeader->NameSize < OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + SmmVariableHeader->DataSize)) {\r
619 //\r
620 // Prevent InfoSize overflow happen\r
621 //\r
622 Status = EFI_ACCESS_DENIED;\r
623 goto EXIT;\r
624 }\r
d17c4eac 625 InfoSize = OFFSET_OF(SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)\r
626 + SmmVariableHeader->DataSize + SmmVariableHeader->NameSize;\r
627\r
628 //\r
629 // SMRAM range check already covered before\r
630 // Data buffer should not contain SMM range\r
631 //\r
5e5bb2a9
SZ
632 if (InfoSize > CommBufferPayloadSize) {\r
633 DEBUG ((EFI_D_ERROR, "SetVariable: Data size exceed communication buffer size limit!\n"));\r
d17c4eac 634 Status = EFI_ACCESS_DENIED;\r
635 goto EXIT;\r
636 }\r
637\r
e83d841f 638 //\r
49395ea0
HW
639 // The VariableSpeculationBarrier() call here is to ensure the previous\r
640 // range/content checks for the CommBuffer have been completed before the\r
641 // subsequent consumption of the CommBuffer content.\r
e83d841f 642 //\r
49395ea0 643 VariableSpeculationBarrier ();\r
9d00d20e
SZ
644 if (SmmVariableHeader->NameSize < sizeof (CHAR16) || SmmVariableHeader->Name[SmmVariableHeader->NameSize/sizeof (CHAR16) - 1] != L'\0') {\r
645 //\r
646 // Make sure VariableName is A Null-terminated string.\r
647 //\r
648 Status = EFI_ACCESS_DENIED;\r
649 goto EXIT;\r
650 }\r
651\r
8a2d4996 652 Status = VariableServiceSetVariable (\r
653 SmmVariableHeader->Name,\r
654 &SmmVariableHeader->Guid,\r
655 SmmVariableHeader->Attributes,\r
656 SmmVariableHeader->DataSize,\r
657 (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize\r
658 );\r
659 break;\r
fa0737a8 660\r
8a2d4996 661 case SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO:\r
5e5bb2a9
SZ
662 if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO)) {\r
663 DEBUG ((EFI_D_ERROR, "QueryVariableInfo: SMM communication buffer size invalid!\n"));\r
664 return EFI_SUCCESS;\r
2445a70e 665 }\r
5e5bb2a9 666 QueryVariableInfo = (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *) SmmVariableFunctionHeader->Data;\r
2445a70e 667\r
8a2d4996 668 Status = VariableServiceQueryVariableInfo (\r
669 QueryVariableInfo->Attributes,\r
670 &QueryVariableInfo->MaximumVariableStorageSize,\r
671 &QueryVariableInfo->RemainingVariableStorageSize,\r
672 &QueryVariableInfo->MaximumVariableSize\r
673 );\r
674 break;\r
675\r
fa0737a8
SZ
676 case SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE:\r
677 if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE)) {\r
678 DEBUG ((EFI_D_ERROR, "GetPayloadSize: SMM communication buffer size invalid!\n"));\r
679 return EFI_SUCCESS;\r
680 }\r
681 GetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;\r
682 GetPayloadSize->VariablePayloadSize = mVariableBufferPayloadSize;\r
683 Status = EFI_SUCCESS;\r
684 break;\r
685\r
8a2d4996 686 case SMM_VARIABLE_FUNCTION_READY_TO_BOOT:\r
876ac395 687 if (AtRuntime()) {\r
688 Status = EFI_UNSUPPORTED;\r
689 break;\r
690 }\r
8021f4c7 691 if (!mEndOfDxe) {\r
f1304280 692 MorLockInitAtEndOfDxe ();\r
b6490426
BB
693 Status = LockVariablePolicy ();\r
694 ASSERT_EFI_ERROR (Status);\r
8021f4c7
SZ
695 mEndOfDxe = TRUE;\r
696 VarCheckLibInitializeAtEndOfDxe (NULL);\r
697 //\r
698 // The initialization for variable quota.\r
699 //\r
700 InitializeVariableQuota ();\r
701 }\r
8a2d4996 702 ReclaimForOS ();\r
703 Status = EFI_SUCCESS;\r
704 break;\r
fa0737a8 705\r
8a2d4996 706 case SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE:\r
707 mAtRuntime = TRUE;\r
708 Status = EFI_SUCCESS;\r
709 break;\r
710\r
711 case SMM_VARIABLE_FUNCTION_GET_STATISTICS:\r
d00ed85e 712 VariableInfo = (VARIABLE_INFO_ENTRY *) SmmVariableFunctionHeader->Data;\r
164a9b67 713 InfoSize = TempCommBufferSize - SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
2445a70e 714\r
715 //\r
fa0737a8
SZ
716 // Do not need to check SmmVariableFunctionHeader->Data in SMRAM here.\r
717 // It is covered by previous CommBuffer check\r
2445a70e 718 //\r
fa0737a8 719\r
62016c1e
SZ
720 //\r
721 // Do not need to check CommBufferSize buffer as it should point to SMRAM\r
722 // that was used by SMM core to cache CommSize from SmmCommunication protocol.\r
723 //\r
2445a70e 724\r
8a2d4996 725 Status = SmmVariableGetStatistics (VariableInfo, &InfoSize);\r
3f5c168f 726 *CommBufferSize = InfoSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
8a2d4996 727 break;\r
728\r
ff843847 729 case SMM_VARIABLE_FUNCTION_LOCK_VARIABLE:\r
51547bb8 730 if (mEndOfDxe) {\r
ff843847 731 Status = EFI_ACCESS_DENIED;\r
51547bb8
RN
732 } else {\r
733 VariableToLock = (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *) SmmVariableFunctionHeader->Data;\r
734 Status = VariableLockRequestToLock (\r
735 NULL,\r
736 VariableToLock->Name,\r
737 &VariableToLock->Guid\r
738 );\r
ff843847 739 }\r
ff843847 740 break;\r
efb01a10
SZ
741 case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET:\r
742 if (mEndOfDxe) {\r
743 Status = EFI_ACCESS_DENIED;\r
744 } else {\r
745 CommVariableProperty = (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *) SmmVariableFunctionHeader->Data;\r
746 Status = VarCheckVariablePropertySet (\r
747 CommVariableProperty->Name,\r
748 &CommVariableProperty->Guid,\r
749 &CommVariableProperty->VariableProperty\r
750 );\r
751 }\r
752 break;\r
753 case SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET:\r
754 if (CommBufferPayloadSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {\r
755 DEBUG ((EFI_D_ERROR, "VarCheckVariablePropertyGet: SMM communication buffer size invalid!\n"));\r
756 return EFI_SUCCESS;\r
757 }\r
758 //\r
759 // Copy the input communicate buffer payload to pre-allocated SMM variable buffer payload.\r
760 //\r
761 CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);\r
762 CommVariableProperty = (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *) mVariableBufferPayload;\r
763 if ((UINTN) (~0) - CommVariableProperty->NameSize < OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {\r
764 //\r
765 // Prevent InfoSize overflow happen\r
766 //\r
767 Status = EFI_ACCESS_DENIED;\r
768 goto EXIT;\r
769 }\r
770 InfoSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + CommVariableProperty->NameSize;\r
771\r
772 //\r
773 // SMRAM range check already covered before\r
774 //\r
775 if (InfoSize > CommBufferPayloadSize) {\r
776 DEBUG ((EFI_D_ERROR, "VarCheckVariablePropertyGet: Data size exceed communication buffer size limit!\n"));\r
777 Status = EFI_ACCESS_DENIED;\r
778 goto EXIT;\r
779 }\r
780\r
e83d841f 781 //\r
49395ea0
HW
782 // The VariableSpeculationBarrier() call here is to ensure the previous\r
783 // range/content checks for the CommBuffer have been completed before the\r
784 // subsequent consumption of the CommBuffer content.\r
e83d841f 785 //\r
49395ea0 786 VariableSpeculationBarrier ();\r
efb01a10
SZ
787 if (CommVariableProperty->NameSize < sizeof (CHAR16) || CommVariableProperty->Name[CommVariableProperty->NameSize/sizeof (CHAR16) - 1] != L'\0') {\r
788 //\r
789 // Make sure VariableName is A Null-terminated string.\r
790 //\r
791 Status = EFI_ACCESS_DENIED;\r
792 goto EXIT;\r
793 }\r
794\r
795 Status = VarCheckVariablePropertyGet (\r
796 CommVariableProperty->Name,\r
797 &CommVariableProperty->Guid,\r
798 &CommVariableProperty->VariableProperty\r
799 );\r
800 CopyMem (SmmVariableFunctionHeader->Data, mVariableBufferPayload, CommBufferPayloadSize);\r
801 break;\r
aab3b9b9
MK
802 case SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT:\r
803 if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT)) {\r
804 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: SMM communication buffer size invalid!\n"));\r
805 Status = EFI_ACCESS_DENIED;\r
806 goto EXIT;\r
807 }\r
808 if (mEndOfDxe) {\r
809 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Cannot init context after end of DXE!\n"));\r
810 Status = EFI_ACCESS_DENIED;\r
811 goto EXIT;\r
812 }\r
813\r
814 //\r
815 // Copy the input communicate buffer payload to the pre-allocated SMM variable payload buffer.\r
816 //\r
817 CopyMem (mVariableBufferPayload, SmmVariableFunctionHeader->Data, CommBufferPayloadSize);\r
818 RuntimeVariableCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) mVariableBufferPayload;\r
819\r
820 //\r
821 // Verify required runtime cache buffers are provided.\r
822 //\r
823 if (RuntimeVariableCacheContext->RuntimeVolatileCache == NULL ||\r
824 RuntimeVariableCacheContext->RuntimeNvCache == NULL ||\r
825 RuntimeVariableCacheContext->PendingUpdate == NULL ||\r
826 RuntimeVariableCacheContext->ReadLock == NULL ||\r
827 RuntimeVariableCacheContext->HobFlushComplete == NULL) {\r
828 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Required runtime cache buffer is NULL!\n"));\r
829 Status = EFI_ACCESS_DENIED;\r
830 goto EXIT;\r
831 }\r
832\r
833 //\r
834 // Verify minimum size requirements for the runtime variable store buffers.\r
835 //\r
836 if ((RuntimeVariableCacheContext->RuntimeHobCache != NULL &&\r
837 RuntimeVariableCacheContext->RuntimeHobCache->Size < sizeof (VARIABLE_STORE_HEADER)) ||\r
838 RuntimeVariableCacheContext->RuntimeVolatileCache->Size < sizeof (VARIABLE_STORE_HEADER) ||\r
839 RuntimeVariableCacheContext->RuntimeNvCache->Size < sizeof (VARIABLE_STORE_HEADER)) {\r
840 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: A runtime cache buffer size is invalid!\n"));\r
841 Status = EFI_ACCESS_DENIED;\r
842 goto EXIT;\r
843 }\r
844\r
845 //\r
846 // Verify runtime buffers do not overlap with SMRAM ranges.\r
847 //\r
848 if (RuntimeVariableCacheContext->RuntimeHobCache != NULL &&\r
849 !VariableSmmIsBufferOutsideSmmValid (\r
850 (UINTN) RuntimeVariableCacheContext->RuntimeHobCache,\r
851 (UINTN) RuntimeVariableCacheContext->RuntimeHobCache->Size)) {\r
852 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime HOB cache buffer in SMRAM or overflow!\n"));\r
853 Status = EFI_ACCESS_DENIED;\r
854 goto EXIT;\r
855 }\r
856 if (!VariableSmmIsBufferOutsideSmmValid (\r
857 (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache,\r
858 (UINTN) RuntimeVariableCacheContext->RuntimeVolatileCache->Size)) {\r
859 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime volatile cache buffer in SMRAM or overflow!\n"));\r
860 Status = EFI_ACCESS_DENIED;\r
861 goto EXIT;\r
862 }\r
863 if (!VariableSmmIsBufferOutsideSmmValid (\r
864 (UINTN) RuntimeVariableCacheContext->RuntimeNvCache,\r
865 (UINTN) RuntimeVariableCacheContext->RuntimeNvCache->Size)) {\r
866 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime non-volatile cache buffer in SMRAM or overflow!\n"));\r
867 Status = EFI_ACCESS_DENIED;\r
868 goto EXIT;\r
869 }\r
870 if (!VariableSmmIsBufferOutsideSmmValid (\r
871 (UINTN) RuntimeVariableCacheContext->PendingUpdate,\r
872 sizeof (*(RuntimeVariableCacheContext->PendingUpdate)))) {\r
873 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache pending update buffer in SMRAM or overflow!\n"));\r
874 Status = EFI_ACCESS_DENIED;\r
875 goto EXIT;\r
876 }\r
877 if (!VariableSmmIsBufferOutsideSmmValid (\r
878 (UINTN) RuntimeVariableCacheContext->ReadLock,\r
879 sizeof (*(RuntimeVariableCacheContext->ReadLock)))) {\r
880 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache read lock buffer in SMRAM or overflow!\n"));\r
881 Status = EFI_ACCESS_DENIED;\r
882 goto EXIT;\r
883 }\r
884 if (!VariableSmmIsBufferOutsideSmmValid (\r
885 (UINTN) RuntimeVariableCacheContext->HobFlushComplete,\r
886 sizeof (*(RuntimeVariableCacheContext->HobFlushComplete)))) {\r
887 DEBUG ((DEBUG_ERROR, "InitRuntimeVariableCacheContext: Runtime cache HOB flush complete buffer in SMRAM or overflow!\n"));\r
888 Status = EFI_ACCESS_DENIED;\r
889 goto EXIT;\r
890 }\r
891\r
892 VariableCacheContext = &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext;\r
893 VariableCacheContext->VariableRuntimeHobCache.Store = RuntimeVariableCacheContext->RuntimeHobCache;\r
894 VariableCacheContext->VariableRuntimeVolatileCache.Store = RuntimeVariableCacheContext->RuntimeVolatileCache;\r
895 VariableCacheContext->VariableRuntimeNvCache.Store = RuntimeVariableCacheContext->RuntimeNvCache;\r
896 VariableCacheContext->PendingUpdate = RuntimeVariableCacheContext->PendingUpdate;\r
897 VariableCacheContext->ReadLock = RuntimeVariableCacheContext->ReadLock;\r
898 VariableCacheContext->HobFlushComplete = RuntimeVariableCacheContext->HobFlushComplete;\r
899\r
900 // Set up the intial pending request since the RT cache needs to be in sync with SMM cache\r
901 VariableCacheContext->VariableRuntimeHobCache.PendingUpdateOffset = 0;\r
902 VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = 0;\r
903 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0 &&\r
904 VariableCacheContext->VariableRuntimeHobCache.Store != NULL) {\r
905 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
906 VariableCacheContext->VariableRuntimeHobCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);\r
907 CopyGuid (&(VariableCacheContext->VariableRuntimeHobCache.Store->Signature), &(VariableCache->Signature));\r
908 }\r
909 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
910 VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateOffset = 0;\r
911 VariableCacheContext->VariableRuntimeVolatileCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);\r
912 CopyGuid (&(VariableCacheContext->VariableRuntimeVolatileCache.Store->Signature), &(VariableCache->Signature));\r
913\r
914 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mNvVariableCache;\r
915 VariableCacheContext->VariableRuntimeNvCache.PendingUpdateOffset = 0;\r
916 VariableCacheContext->VariableRuntimeNvCache.PendingUpdateLength = (UINT32) ((UINTN) GetEndPointer (VariableCache) - (UINTN) VariableCache);\r
917 CopyGuid (&(VariableCacheContext->VariableRuntimeNvCache.Store->Signature), &(VariableCache->Signature));\r
918\r
919 *(VariableCacheContext->PendingUpdate) = TRUE;\r
920 *(VariableCacheContext->ReadLock) = FALSE;\r
921 *(VariableCacheContext->HobFlushComplete) = FALSE;\r
922\r
923 Status = EFI_SUCCESS;\r
924 break;\r
925 case SMM_VARIABLE_FUNCTION_SYNC_RUNTIME_CACHE:\r
926 Status = FlushPendingRuntimeVariableCacheUpdates ();\r
927 break;\r
928 case SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO:\r
929 if (CommBufferPayloadSize < sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO)) {\r
930 DEBUG ((DEBUG_ERROR, "GetRuntimeCacheInfo: SMM communication buffer size invalid!\n"));\r
931 return EFI_SUCCESS;\r
932 }\r
933 GetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;\r
934\r
935 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase > 0) {\r
936 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
937 GetRuntimeCacheInfo->TotalHobStorageSize = VariableCache->Size;\r
938 } else {\r
939 GetRuntimeCacheInfo->TotalHobStorageSize = 0;\r
940 }\r
941\r
942 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
943 GetRuntimeCacheInfo->TotalVolatileStorageSize = VariableCache->Size;\r
944 VariableCache = (VARIABLE_STORE_HEADER *) (UINTN) mNvVariableCache;\r
945 GetRuntimeCacheInfo->TotalNvStorageSize = (UINTN) VariableCache->Size;\r
946 GetRuntimeCacheInfo->AuthenticatedVariableUsage = mVariableModuleGlobal->VariableGlobal.AuthFormat;\r
947\r
948 Status = EFI_SUCCESS;\r
949 break;\r
ff843847 950\r
8a2d4996 951 default:\r
8a2d4996 952 Status = EFI_UNSUPPORTED;\r
953 }\r
954\r
2445a70e 955EXIT:\r
956\r
8a2d4996 957 SmmVariableFunctionHeader->ReturnStatus = Status;\r
958\r
959 return EFI_SUCCESS;\r
960}\r
961\r
ff843847
RN
962/**\r
963 SMM END_OF_DXE protocol notification event handler.\r
964\r
965 @param Protocol Points to the protocol's unique identifier\r
966 @param Interface Points to the interface instance\r
967 @param Handle The handle on which the interface was installed\r
968\r
969 @retval EFI_SUCCESS SmmEndOfDxeCallback runs successfully\r
970\r
971**/\r
972EFI_STATUS\r
973EFIAPI\r
974SmmEndOfDxeCallback (\r
975 IN CONST EFI_GUID *Protocol,\r
976 IN VOID *Interface,\r
977 IN EFI_HANDLE Handle\r
978 )\r
979{\r
b6490426
BB
980 EFI_STATUS Status;\r
981\r
8021f4c7 982 DEBUG ((EFI_D_INFO, "[Variable]SMM_END_OF_DXE is signaled\n"));\r
f1304280 983 MorLockInitAtEndOfDxe ();\r
b6490426
BB
984 Status = LockVariablePolicy ();\r
985 ASSERT_EFI_ERROR (Status);\r
ff843847 986 mEndOfDxe = TRUE;\r
8021f4c7 987 VarCheckLibInitializeAtEndOfDxe (NULL);\r
4edb1866
SZ
988 //\r
989 // The initialization for variable quota.\r
990 //\r
991 InitializeVariableQuota ();\r
0fb5e515
SZ
992 if (PcdGetBool (PcdReclaimVariableSpaceAtEndOfDxe)) {\r
993 ReclaimForOS ();\r
994 }\r
8021f4c7 995\r
ff843847
RN
996 return EFI_SUCCESS;\r
997}\r
8a2d4996 998\r
b59fd889
SZ
999/**\r
1000 Initializes variable write service for SMM.\r
1001\r
1002**/\r
1003VOID\r
1004VariableWriteServiceInitializeSmm (\r
1005 VOID\r
1006 )\r
1007{\r
1008 EFI_STATUS Status;\r
1009\r
1010 Status = VariableWriteServiceInitialize ();\r
1011 if (EFI_ERROR (Status)) {\r
1012 DEBUG ((DEBUG_ERROR, "Variable write service initialization failed. Status = %r\n", Status));\r
1013 }\r
1014\r
1015 //\r
1016 // Notify the variable wrapper driver the variable write service is ready\r
1017 //\r
1018 VariableNotifySmmWriteReady ();\r
1019}\r
1020\r
8a2d4996 1021/**\r
1022 SMM Fault Tolerant Write protocol notification event handler.\r
1023\r
fa0737a8 1024 Non-Volatile variable write may needs FTW protocol to reclaim when\r
8a2d4996 1025 writting variable.\r
fa0737a8 1026\r
8a2d4996 1027 @param Protocol Points to the protocol's unique identifier\r
1028 @param Interface Points to the interface instance\r
1029 @param Handle The handle on which the interface was installed\r
1030\r
1031 @retval EFI_SUCCESS SmmEventCallback runs successfully\r
1032 @retval EFI_NOT_FOUND The Fvb protocol for variable is not found.\r
fa0737a8 1033\r
8a2d4996 1034 **/\r
1035EFI_STATUS\r
1036EFIAPI\r
1037SmmFtwNotificationEvent (\r
1038 IN CONST EFI_GUID *Protocol,\r
1039 IN VOID *Interface,\r
1040 IN EFI_HANDLE Handle\r
1041 )\r
1042{\r
1043 EFI_STATUS Status;\r
904e0ca9 1044 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
8a2d4996 1045 EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;\r
1046 EFI_SMM_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;\r
1047 EFI_PHYSICAL_ADDRESS NvStorageVariableBase;\r
2c4b18e0 1048 UINTN FtwMaxBlockSize;\r
fa0737a8 1049\r
8a2d4996 1050 if (mVariableModuleGlobal->FvbInstance != NULL) {\r
1051 return EFI_SUCCESS;\r
1052 }\r
1053\r
1054 //\r
1055 // Ensure SMM FTW protocol is installed.\r
1056 //\r
5c7fa429 1057 Status = GetFtwProtocol ((VOID **)&FtwProtocol);\r
8a2d4996 1058 if (EFI_ERROR (Status)) {\r
1059 return Status;\r
1060 }\r
1061\r
2c4b18e0
SZ
1062 Status = FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);\r
1063 if (!EFI_ERROR (Status)) {\r
1064 ASSERT (PcdGet32 (PcdFlashNvStorageVariableSize) <= FtwMaxBlockSize);\r
1065 }\r
1066\r
904e0ca9
SZ
1067 NvStorageVariableBase = NV_STORAGE_VARIABLE_BASE;\r
1068 VariableStoreBase = NvStorageVariableBase + mNvFvHeaderCache->HeaderLength;\r
1069\r
1070 //\r
1071 // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.\r
1072 //\r
1073 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
1074\r
8a2d4996 1075 //\r
1076 // Find the proper FVB protocol for variable.\r
1077 //\r
8a2d4996 1078 Status = GetFvbInfoByAddress (NvStorageVariableBase, NULL, &FvbProtocol);\r
1079 if (EFI_ERROR (Status)) {\r
1080 return EFI_NOT_FOUND;\r
1081 }\r
1082\r
1083 mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
fa0737a8 1084\r
8a2d4996 1085 //\r
b59fd889 1086 // Initializes variable write service after FTW was ready.\r
8a2d4996 1087 //\r
b59fd889 1088 VariableWriteServiceInitializeSmm ();\r
fa0737a8 1089\r
8a2d4996 1090 return EFI_SUCCESS;\r
1091}\r
1092\r
1093\r
1094/**\r
1095 Variable Driver main entry point. The Variable driver places the 4 EFI\r
fa0737a8 1096 runtime services in the EFI System Table and installs arch protocols\r
d00ed85e 1097 for variable read and write services being available. It also registers\r
8a2d4996 1098 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
1099\r
8a2d4996 1100 @retval EFI_SUCCESS Variable service successfully initialized.\r
1101\r
1102**/\r
1103EFI_STATUS\r
1104EFIAPI\r
a855f63e
AB
1105MmVariableServiceInitialize (\r
1106 VOID\r
8a2d4996 1107 )\r
1108{\r
1109 EFI_STATUS Status;\r
1110 EFI_HANDLE VariableHandle;\r
1111 VOID *SmmFtwRegistration;\r
ff843847 1112 VOID *SmmEndOfDxeRegistration;\r
2445a70e 1113\r
8a2d4996 1114 //\r
1115 // Variable initialize.\r
1116 //\r
1117 Status = VariableCommonInitialize ();\r
1118 ASSERT_EFI_ERROR (Status);\r
1119\r
1120 //\r
1121 // Install the Smm Variable Protocol on a new handle.\r
1122 //\r
1123 VariableHandle = NULL;\r
a855f63e 1124 Status = gMmst->MmInstallProtocolInterface (\r
8a2d4996 1125 &VariableHandle,\r
1126 &gEfiSmmVariableProtocolGuid,\r
1127 EFI_NATIVE_INTERFACE,\r
1128 &gSmmVariable\r
1129 );\r
1130 ASSERT_EFI_ERROR (Status);\r
1131\r
a855f63e 1132 Status = gMmst->MmInstallProtocolInterface (\r
efb01a10
SZ
1133 &VariableHandle,\r
1134 &gEdkiiSmmVarCheckProtocolGuid,\r
1135 EFI_NATIVE_INTERFACE,\r
1136 &mSmmVarCheck\r
1137 );\r
1138 ASSERT_EFI_ERROR (Status);\r
1139\r
04401023
MK
1140 mVariableBufferPayloadSize = GetMaxVariableSize () +\r
1141 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) -\r
1142 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);\r
5e5bb2a9 1143\r
a855f63e 1144 Status = gMmst->MmAllocatePool (\r
5e5bb2a9
SZ
1145 EfiRuntimeServicesData,\r
1146 mVariableBufferPayloadSize,\r
1147 (VOID **)&mVariableBufferPayload\r
1148 );\r
1149 ASSERT_EFI_ERROR (Status);\r
1150\r
8a2d4996 1151 ///\r
1152 /// Register SMM variable SMI handler\r
1153 ///\r
1154 VariableHandle = NULL;\r
a855f63e 1155 Status = gMmst->MmiHandlerRegister (SmmVariableHandler, &gEfiSmmVariableProtocolGuid, &VariableHandle);\r
8a2d4996 1156 ASSERT_EFI_ERROR (Status);\r
fa0737a8 1157\r
8a2d4996 1158 //\r
1159 // Notify the variable wrapper driver the variable service is ready\r
1160 //\r
a855f63e 1161 VariableNotifySmmReady ();\r
fa0737a8 1162\r
ff843847
RN
1163 //\r
1164 // Register EFI_SMM_END_OF_DXE_PROTOCOL_GUID notify function.\r
1165 //\r
a855f63e
AB
1166 Status = gMmst->MmRegisterProtocolNotify (\r
1167 &gEfiMmEndOfDxeProtocolGuid,\r
ff843847
RN
1168 SmmEndOfDxeCallback,\r
1169 &SmmEndOfDxeRegistration\r
1170 );\r
1171 ASSERT_EFI_ERROR (Status);\r
1172\r
7cd69959
SZ
1173 if (!PcdGetBool (PcdEmuVariableNvModeEnable)) {\r
1174 //\r
1175 // Register FtwNotificationEvent () notify function.\r
1176 //\r
1177 Status = gMmst->MmRegisterProtocolNotify (\r
1178 &gEfiSmmFaultTolerantWriteProtocolGuid,\r
1179 SmmFtwNotificationEvent,\r
1180 &SmmFtwRegistration\r
1181 );\r
1182 ASSERT_EFI_ERROR (Status);\r
1183\r
1184 SmmFtwNotificationEvent (NULL, NULL, NULL);\r
1185 } else {\r
1186 //\r
1187 // Emulated non-volatile variable mode does not depend on FVB and FTW.\r
1188 //\r
1189 VariableWriteServiceInitializeSmm ();\r
1190 }\r
fa0737a8 1191\r
8a2d4996 1192 return EFI_SUCCESS;\r
1193}\r
1194\r
1195\r