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