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