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