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