]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
MdeModulePkg/Variable: Initialize local variable "Variable"
[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
593 //\r
594 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service\r
595 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent\r
596 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime\r
597 // cache read lock should always be free when entering this function.\r
598 //\r
599 ASSERT (!mVariableRuntimeCacheReadLock);\r
600\r
601 mVariableRuntimeCacheReadLock = TRUE;\r
602 CheckForRuntimeCacheSync ();\r
603\r
604 if (!mVariableRuntimeCachePendingUpdate) {\r
605 //\r
606 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
607 // The index and attributes mapping must be kept in this order as FindVariable\r
608 // makes use of this mapping to implement search algorithm.\r
609 //\r
610 VariableStoreList[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;\r
611 VariableStoreList[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer;\r
612 VariableStoreList[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer;\r
613\r
614 for (StoreType = (VARIABLE_STORE_TYPE) 0; StoreType < VariableStoreTypeMax; StoreType++) {\r
615 if (VariableStoreList[StoreType] == NULL) {\r
616 continue;\r
617 }\r
618\r
619 RtPtrTrack.StartPtr = GetStartPointer (VariableStoreList[StoreType]);\r
620 RtPtrTrack.EndPtr = GetEndPointer (VariableStoreList[StoreType]);\r
621 RtPtrTrack.Volatile = (BOOLEAN) (StoreType == VariableStoreTypeVolatile);\r
622\r
623 Status = FindVariableEx (VariableName, VendorGuid, FALSE, &RtPtrTrack, mVariableAuthFormat);\r
624 if (!EFI_ERROR (Status)) {\r
625 break;\r
626 }\r
627 }\r
628\r
629 if (!EFI_ERROR (Status)) {\r
630 //\r
631 // Get data size\r
632 //\r
633 TempDataSize = DataSizeOfVariable (RtPtrTrack.CurrPtr, mVariableAuthFormat);\r
634 ASSERT (TempDataSize != 0);\r
635\r
636 if (*DataSize >= TempDataSize) {\r
637 if (Data == NULL) {\r
638 Status = EFI_INVALID_PARAMETER;\r
639 goto Done;\r
640 }\r
641\r
642 CopyMem (Data, GetVariableDataPtr (RtPtrTrack.CurrPtr, mVariableAuthFormat), TempDataSize);\r
643 if (Attributes != NULL) {\r
644 *Attributes = RtPtrTrack.CurrPtr->Attributes;\r
645 }\r
646\r
647 *DataSize = TempDataSize;\r
648\r
649 UpdateVariableInfo (VariableName, VendorGuid, RtPtrTrack.Volatile, TRUE, FALSE, FALSE, TRUE, &mVariableInfo);\r
650\r
651 Status = EFI_SUCCESS;\r
652 goto Done;\r
653 } else {\r
654 *DataSize = TempDataSize;\r
655 Status = EFI_BUFFER_TOO_SMALL;\r
656 goto Done;\r
657 }\r
658 }\r
659 }\r
660\r
661Done:\r
662 mVariableRuntimeCacheReadLock = FALSE;\r
663\r
664 return Status;\r
665}\r
666\r
667/**\r
668 Finds the given variable in a variable store in SMM.\r
669\r
670 Caution: This function may receive untrusted input.\r
671 The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
672\r
673 @param[in] VariableName Name of Variable to be found.\r
674 @param[in] VendorGuid Variable vendor GUID.\r
675 @param[out] Attributes Attribute value of the variable found.\r
676 @param[in, out] DataSize Size of Data found. If size is less than the\r
677 data, this value contains the required size.\r
678 @param[out] Data Data pointer.\r
679\r
680 @retval EFI_SUCCESS Found the specified variable.\r
681 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
682 @retval EFI_NOT_FOUND The specified variable could not be found.\r
683\r
684**/\r
685EFI_STATUS\r
686FindVariableInSmm (\r
687 IN CHAR16 *VariableName,\r
688 IN EFI_GUID *VendorGuid,\r
689 OUT UINT32 *Attributes OPTIONAL,\r
690 IN OUT UINTN *DataSize,\r
691 OUT VOID *Data OPTIONAL\r
8a2d4996 692 )\r
693{\r
694 EFI_STATUS Status;\r
695 UINTN PayloadSize;\r
696 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
3a146f2a 697 UINTN TempDataSize;\r
9d00d20e 698 UINTN VariableNameSize;\r
8a2d4996 699\r
700 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
701 return EFI_INVALID_PARAMETER;\r
702 }\r
703\r
3a146f2a 704 TempDataSize = *DataSize;\r
9d00d20e 705 VariableNameSize = StrSize (VariableName);\r
4e1005ec 706 SmmVariableHeader = NULL;\r
3a146f2a 707\r
708 //\r
709 // If VariableName exceeds SMM payload limit. Return failure\r
710 //\r
5e5bb2a9 711 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
3588bb35
SZ
712 return EFI_INVALID_PARAMETER;\r
713 }\r
714\r
8a2d4996 715 //\r
716 // Init the communicate buffer. The buffer data size is:\r
6ed1ec59 717 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
8a2d4996 718 //\r
5e5bb2a9 719 if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {\r
3a146f2a 720 //\r
721 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
722 //\r
5e5bb2a9 723 TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;\r
3a146f2a 724 }\r
9d00d20e 725 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
3a146f2a 726\r
aab3b9b9 727 Status = InitCommunicateBuffer ((VOID **) &SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
8a2d4996 728 if (EFI_ERROR (Status)) {\r
6ed1ec59 729 goto Done;\r
8a2d4996 730 }\r
731 ASSERT (SmmVariableHeader != NULL);\r
732\r
733 CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
3a146f2a 734 SmmVariableHeader->DataSize = TempDataSize;\r
9d00d20e 735 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 736 if (Attributes == NULL) {\r
737 SmmVariableHeader->Attributes = 0;\r
738 } else {\r
739 SmmVariableHeader->Attributes = *Attributes;\r
740 }\r
741 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
742\r
743 //\r
744 // Send data to SMM.\r
745 //\r
746 Status = SendCommunicateBuffer (PayloadSize);\r
747\r
748 //\r
749 // Get data from SMM.\r
750 //\r
3a146f2a 751 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
752 //\r
753 // SMM CommBuffer DataSize can be a trimed value\r
754 // Only update DataSize when needed\r
755 //\r
756 *DataSize = SmmVariableHeader->DataSize;\r
757 }\r
8a2d4996 758 if (Attributes != NULL) {\r
759 *Attributes = SmmVariableHeader->Attributes;\r
760 }\r
761\r
762 if (EFI_ERROR (Status)) {\r
6ed1ec59 763 goto Done;\r
8a2d4996 764 }\r
765\r
82e47eb2
SZ
766 if (Data != NULL) {\r
767 CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
768 } else {\r
769 Status = EFI_INVALID_PARAMETER;\r
770 }\r
8a2d4996 771\r
6ed1ec59 772Done:\r
8a2d4996 773 return Status;\r
774}\r
775\r
aab3b9b9
MK
776/**\r
777 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
778\r
779 Caution: This function may receive untrusted input.\r
780 The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
781\r
782 @param[in] VariableName Name of Variable to be found.\r
783 @param[in] VendorGuid Variable vendor GUID.\r
784 @param[out] Attributes Attribute value of the variable found.\r
785 @param[in, out] DataSize Size of Data found. If size is less than the\r
786 data, this value contains the required size.\r
787 @param[out] Data Data pointer.\r
788\r
789 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
790 @retval EFI_SUCCESS Find the specified variable.\r
791 @retval EFI_NOT_FOUND Not found.\r
792 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
793\r
794**/\r
795EFI_STATUS\r
796EFIAPI\r
797RuntimeServiceGetVariable (\r
798 IN CHAR16 *VariableName,\r
799 IN EFI_GUID *VendorGuid,\r
800 OUT UINT32 *Attributes OPTIONAL,\r
801 IN OUT UINTN *DataSize,\r
802 OUT VOID *Data\r
803 )\r
804{\r
805 EFI_STATUS Status;\r
806\r
807 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
808 return EFI_INVALID_PARAMETER;\r
809 }\r
810 if (VariableName[0] == 0) {\r
811 return EFI_NOT_FOUND;\r
812 }\r
813\r
814 AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
815 if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
816 Status = FindVariableInRuntimeCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
817 } else {\r
818 Status = FindVariableInSmm (VariableName, VendorGuid, Attributes, DataSize, Data);\r
819 }\r
820 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
821\r
822 return Status;\r
823}\r
8a2d4996 824\r
825/**\r
6f9838f3 826 Finds the next available variable in a runtime cache variable store.\r
8a2d4996 827\r
828 @param[in, out] VariableNameSize Size of the variable name.\r
829 @param[in, out] VariableName Pointer to variable name.\r
830 @param[in, out] VendorGuid Variable Vendor Guid.\r
831\r
832 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
833 @retval EFI_SUCCESS Find the specified variable.\r
834 @retval EFI_NOT_FOUND Not found.\r
835 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
836\r
837**/\r
838EFI_STATUS\r
6f9838f3
MK
839GetNextVariableNameInRuntimeCache (\r
840 IN OUT UINTN *VariableNameSize,\r
841 IN OUT CHAR16 *VariableName,\r
842 IN OUT EFI_GUID *VendorGuid\r
843 )\r
844{\r
845 EFI_STATUS Status;\r
846 UINTN VarNameSize;\r
847 VARIABLE_HEADER *VariablePtr;\r
848 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
849\r
850 Status = EFI_NOT_FOUND;\r
851\r
852 //\r
853 // The UEFI specification restricts Runtime Services callers from invoking the same or certain other Runtime Service\r
854 // functions prior to completion and return from a previous Runtime Service call. These restrictions prevent\r
855 // a GetVariable () or GetNextVariable () call from being issued until a prior call has returned. The runtime\r
856 // cache read lock should always be free when entering this function.\r
857 //\r
858 ASSERT (!mVariableRuntimeCacheReadLock);\r
859\r
860 CheckForRuntimeCacheSync ();\r
861\r
862 mVariableRuntimeCacheReadLock = TRUE;\r
863 if (!mVariableRuntimeCachePendingUpdate) {\r
864 //\r
865 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
866 // The index and attributes mapping must be kept in this order as FindVariable\r
867 // makes use of this mapping to implement search algorithm.\r
868 //\r
869 VariableStoreHeader[VariableStoreTypeVolatile] = mVariableRuntimeVolatileCacheBuffer;\r
870 VariableStoreHeader[VariableStoreTypeHob] = mVariableRuntimeHobCacheBuffer;\r
871 VariableStoreHeader[VariableStoreTypeNv] = mVariableRuntimeNvCacheBuffer;\r
872\r
873 Status = VariableServiceGetNextVariableInternal (\r
874 VariableName,\r
875 VendorGuid,\r
876 VariableStoreHeader,\r
877 &VariablePtr,\r
878 mVariableAuthFormat\r
879 );\r
880 if (!EFI_ERROR (Status)) {\r
881 VarNameSize = NameSizeOfVariable (VariablePtr, mVariableAuthFormat);\r
882 ASSERT (VarNameSize != 0);\r
883 if (VarNameSize <= *VariableNameSize) {\r
884 CopyMem (VariableName, GetVariableNamePtr (VariablePtr, mVariableAuthFormat), VarNameSize);\r
885 CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr, mVariableAuthFormat), sizeof (EFI_GUID));\r
886 Status = EFI_SUCCESS;\r
887 } else {\r
888 Status = EFI_BUFFER_TOO_SMALL;\r
889 }\r
890\r
891 *VariableNameSize = VarNameSize;\r
892 }\r
893 }\r
894 mVariableRuntimeCacheReadLock = FALSE;\r
895\r
896 return Status;\r
897}\r
898\r
899/**\r
900 Finds the next available variable in a SMM variable store.\r
901\r
902 @param[in, out] VariableNameSize Size of the variable name.\r
903 @param[in, out] VariableName Pointer to variable name.\r
904 @param[in, out] VendorGuid Variable Vendor Guid.\r
905\r
906 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
907 @retval EFI_SUCCESS Find the specified variable.\r
908 @retval EFI_NOT_FOUND Not found.\r
909 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
910\r
911**/\r
912EFI_STATUS\r
913GetNextVariableNameInSmm (\r
8a2d4996 914 IN OUT UINTN *VariableNameSize,\r
915 IN OUT CHAR16 *VariableName,\r
916 IN OUT EFI_GUID *VendorGuid\r
917 )\r
918{\r
919 EFI_STATUS Status;\r
920 UINTN PayloadSize;\r
921 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
9d00d20e
SZ
922 UINTN OutVariableNameSize;\r
923 UINTN InVariableNameSize;\r
8a2d4996 924\r
9d00d20e
SZ
925 OutVariableNameSize = *VariableNameSize;\r
926 InVariableNameSize = StrSize (VariableName);\r
4e1005ec 927 SmmGetNextVariableName = NULL;\r
0c55190f 928\r
929 //\r
930 // If input string exceeds SMM payload limit. Return failure\r
931 //\r
5e5bb2a9 932 if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
3588bb35
SZ
933 return EFI_INVALID_PARAMETER;\r
934 }\r
935\r
8a2d4996 936 //\r
937 // Init the communicate buffer. The buffer data size is:\r
938 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
939 //\r
5e5bb2a9 940 if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
0c55190f 941 //\r
942 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
943 //\r
5e5bb2a9 944 OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
0c55190f 945 }\r
946 //\r
947 // Payload should be Guid + NameSize + MAX of Input & Output buffer\r
948 //\r
9d00d20e 949 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);\r
0c55190f 950\r
5c7fa429 951 Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
8a2d4996 952 if (EFI_ERROR (Status)) {\r
6ed1ec59 953 goto Done;\r
8a2d4996 954 }\r
955 ASSERT (SmmGetNextVariableName != NULL);\r
956\r
0c55190f 957 //\r
958 // SMM comm buffer->NameSize is buffer size for return string\r
959 //\r
9d00d20e 960 SmmGetNextVariableName->NameSize = OutVariableNameSize;\r
0c55190f 961\r
8a2d4996 962 CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
0c55190f 963 //\r
964 // Copy whole string\r
965 //\r
9d00d20e
SZ
966 CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);\r
967 if (OutVariableNameSize > InVariableNameSize) {\r
968 ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
969 }\r
8a2d4996 970\r
971 //\r
972 // Send data to SMM\r
973 //\r
974 Status = SendCommunicateBuffer (PayloadSize);\r
975\r
976 //\r
977 // Get data from SMM.\r
978 //\r
9d00d20e
SZ
979 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
980 //\r
981 // SMM CommBuffer NameSize can be a trimed value\r
982 // Only update VariableNameSize when needed\r
983 //\r
984 *VariableNameSize = SmmGetNextVariableName->NameSize;\r
985 }\r
8a2d4996 986 if (EFI_ERROR (Status)) {\r
6ed1ec59 987 goto Done;\r
8a2d4996 988 }\r
fa0737a8 989\r
8a2d4996 990 CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
fa0737a8 991 CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);\r
8a2d4996 992\r
6ed1ec59 993Done:\r
6f9838f3
MK
994 return Status;\r
995}\r
996\r
997/**\r
998 This code Finds the Next available variable.\r
999\r
1000 @param[in, out] VariableNameSize Size of the variable name.\r
1001 @param[in, out] VariableName Pointer to variable name.\r
1002 @param[in, out] VendorGuid Variable Vendor Guid.\r
1003\r
1004 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
1005 @retval EFI_SUCCESS Find the specified variable.\r
1006 @retval EFI_NOT_FOUND Not found.\r
1007 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
1008\r
1009**/\r
1010EFI_STATUS\r
1011EFIAPI\r
1012RuntimeServiceGetNextVariableName (\r
1013 IN OUT UINTN *VariableNameSize,\r
1014 IN OUT CHAR16 *VariableName,\r
1015 IN OUT EFI_GUID *VendorGuid\r
1016 )\r
1017{\r
1018 EFI_STATUS Status;\r
1019 UINTN MaxLen;\r
1020\r
1021 Status = EFI_NOT_FOUND;\r
1022\r
1023 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
1024 return EFI_INVALID_PARAMETER;\r
1025 }\r
1026\r
1027 //\r
1028 // Calculate the possible maximum length of name string, including the Null terminator.\r
1029 //\r
1030 MaxLen = *VariableNameSize / sizeof (CHAR16);\r
1031 if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {\r
1032 //\r
1033 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,\r
1034 // follow spec to return EFI_INVALID_PARAMETER.\r
1035 //\r
1036 return EFI_INVALID_PARAMETER;\r
1037 }\r
1038\r
1039 AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
1040 if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
1041 Status = GetNextVariableNameInRuntimeCache (VariableNameSize, VariableName, VendorGuid);\r
1042 } else {\r
1043 Status = GetNextVariableNameInSmm (VariableNameSize, VariableName, VendorGuid);\r
1044 }\r
6ed1ec59 1045 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
6f9838f3 1046\r
8a2d4996 1047 return Status;\r
1048}\r
1049\r
1050/**\r
1051 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
1052\r
18a7dbbc
SZ
1053 Caution: This function may receive untrusted input.\r
1054 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.\r
1055\r
8a2d4996 1056 @param[in] VariableName Name of Variable to be found.\r
1057 @param[in] VendorGuid Variable vendor GUID.\r
1058 @param[in] Attributes Attribute value of the variable found\r
1059 @param[in] DataSize Size of Data found. If size is less than the\r
1060 data, this value contains the required size.\r
1061 @param[in] Data Data pointer.\r
1062\r
1063 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
1064 @retval EFI_SUCCESS Set successfully.\r
1065 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
1066 @retval EFI_NOT_FOUND Not found.\r
1067 @retval EFI_WRITE_PROTECTED Variable is read-only.\r
1068\r
1069**/\r
1070EFI_STATUS\r
1071EFIAPI\r
1072RuntimeServiceSetVariable (\r
1073 IN CHAR16 *VariableName,\r
1074 IN EFI_GUID *VendorGuid,\r
1075 IN UINT32 Attributes,\r
1076 IN UINTN DataSize,\r
1077 IN VOID *Data\r
1078 )\r
1079{\r
1080 EFI_STATUS Status;\r
fa0737a8 1081 UINTN PayloadSize;\r
8a2d4996 1082 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
9d00d20e 1083 UINTN VariableNameSize;\r
fa0737a8 1084\r
8a2d4996 1085 //\r
1086 // Check input parameters.\r
1087 //\r
1088 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
1089 return EFI_INVALID_PARAMETER;\r
fa0737a8 1090 }\r
8a2d4996 1091\r
1092 if (DataSize != 0 && Data == NULL) {\r
1093 return EFI_INVALID_PARAMETER;\r
1094 }\r
6ed1ec59 1095\r
9d00d20e 1096 VariableNameSize = StrSize (VariableName);\r
4e1005ec 1097 SmmVariableHeader = NULL;\r
3588bb35 1098\r
5e5bb2a9
SZ
1099 //\r
1100 // If VariableName or DataSize exceeds SMM payload limit. Return failure\r
1101 //\r
1102 if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
1103 (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){\r
56251c66 1104 return EFI_INVALID_PARAMETER;\r
1105 }\r
1106\r
6ed1ec59 1107 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
fa0737a8 1108\r
8a2d4996 1109 //\r
1110 // Init the communicate buffer. The buffer data size is:\r
1111 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
1112 //\r
9d00d20e 1113 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;\r
5c7fa429 1114 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
8a2d4996 1115 if (EFI_ERROR (Status)) {\r
6ed1ec59 1116 goto Done;\r
8a2d4996 1117 }\r
1118 ASSERT (SmmVariableHeader != NULL);\r
1119\r
1120 CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
1121 SmmVariableHeader->DataSize = DataSize;\r
9d00d20e 1122 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 1123 SmmVariableHeader->Attributes = Attributes;\r
1124 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
1125 CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
1126\r
1127 //\r
1128 // Send data to SMM.\r
1129 //\r
1130 Status = SendCommunicateBuffer (PayloadSize);\r
6ed1ec59
SZ
1131\r
1132Done:\r
1133 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
fa0737a8
SZ
1134\r
1135 if (!EfiAtRuntime ()) {\r
1136 if (!EFI_ERROR (Status)) {\r
1137 SecureBootHook (\r
1138 VariableName,\r
1139 VendorGuid\r
1140 );\r
1141 }\r
1142 }\r
8a2d4996 1143 return Status;\r
1144}\r
1145\r
1146\r
1147/**\r
1148 This code returns information about the EFI variables.\r
1149\r
1150 @param[in] Attributes Attributes bitmask to specify the type of variables\r
1151 on which to return information.\r
1152 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
1153 for the EFI variables associated with the attributes specified.\r
1154 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
1155 for EFI variables associated with the attributes specified.\r
1156 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
1157 associated with the attributes specified.\r
1158\r
1159 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
1160 @retval EFI_SUCCESS Query successfully.\r
1161 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.\r
1162\r
1163**/\r
1164EFI_STATUS\r
1165EFIAPI\r
1166RuntimeServiceQueryVariableInfo (\r
1167 IN UINT32 Attributes,\r
1168 OUT UINT64 *MaximumVariableStorageSize,\r
1169 OUT UINT64 *RemainingVariableStorageSize,\r
1170 OUT UINT64 *MaximumVariableSize\r
1171 )\r
1172{\r
1173 EFI_STATUS Status;\r
1174 UINTN PayloadSize;\r
1175 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
1176\r
4e1005ec
ED
1177 SmmQueryVariableInfo = NULL;\r
1178\r
8a2d4996 1179 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
1180 return EFI_INVALID_PARAMETER;\r
1181 }\r
6ed1ec59
SZ
1182\r
1183 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
1184\r
8a2d4996 1185 //\r
1186 // Init the communicate buffer. The buffer data size is:\r
1187 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
1188 //\r
d00ed85e 1189 PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
5c7fa429 1190 Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
8a2d4996 1191 if (EFI_ERROR (Status)) {\r
6ed1ec59 1192 goto Done;\r
8a2d4996 1193 }\r
1194 ASSERT (SmmQueryVariableInfo != NULL);\r
1195\r
1196 SmmQueryVariableInfo->Attributes = Attributes;\r
1197\r
1198 //\r
1199 // Send data to SMM.\r
1200 //\r
1201 Status = SendCommunicateBuffer (PayloadSize);\r
1202 if (EFI_ERROR (Status)) {\r
6ed1ec59 1203 goto Done;\r
8a2d4996 1204 }\r
1205\r
1206 //\r
1207 // Get data from SMM.\r
1208 //\r
1209 *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;\r
1210 *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
fa0737a8 1211 *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;\r
6ed1ec59
SZ
1212\r
1213Done:\r
1214 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
aab9212f 1215 return Status;\r
8a2d4996 1216}\r
1217\r
1218\r
1219/**\r
1220 Exit Boot Services Event notification handler.\r
1221\r
1222 Notify SMM variable driver about the event.\r
1223\r
1224 @param[in] Event Event whose notification function is being invoked.\r
1225 @param[in] Context Pointer to the notification function's context.\r
1226\r
1227**/\r
1228VOID\r
1229EFIAPI\r
1230OnExitBootServices (\r
1231 IN EFI_EVENT Event,\r
1232 IN VOID *Context\r
1233 )\r
1234{\r
1235 //\r
1236 // Init the communicate buffer. The buffer data size is:\r
1237 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
1238 //\r
fa0737a8 1239 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);\r
8a2d4996 1240\r
1241 //\r
1242 // Send data to SMM.\r
1243 //\r
1244 SendCommunicateBuffer (0);\r
1245}\r
1246\r
1247\r
1248/**\r
1249 On Ready To Boot Services Event notification handler.\r
1250\r
1251 Notify SMM variable driver about the event.\r
1252\r
1253 @param[in] Event Event whose notification function is being invoked\r
1254 @param[in] Context Pointer to the notification function's context\r
1255\r
1256**/\r
1257VOID\r
1258EFIAPI\r
1259OnReadyToBoot (\r
1260 IN EFI_EVENT Event,\r
1261 IN VOID *Context\r
1262 )\r
1263{\r
1264 //\r
1265 // Init the communicate buffer. The buffer data size is:\r
1266 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
1267 //\r
1268 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
fa0737a8 1269\r
8a2d4996 1270 //\r
1271 // Send data to SMM.\r
1272 //\r
1273 SendCommunicateBuffer (0);\r
fa0737a8 1274\r
aab3b9b9
MK
1275 //\r
1276 // Install the system configuration table for variable info data captured\r
1277 //\r
1278 if (FeaturePcdGet (PcdEnableVariableRuntimeCache) && FeaturePcdGet (PcdVariableCollectStatistics)) {\r
1279 if (mVariableAuthFormat) {\r
1280 gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, mVariableInfo);\r
1281 } else {\r
1282 gBS->InstallConfigurationTable (&gEfiVariableGuid, mVariableInfo);\r
1283 }\r
1284 }\r
1285\r
fa0737a8 1286 gBS->CloseEvent (Event);\r
8a2d4996 1287}\r
1288\r
1289\r
1290/**\r
1291 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
1292\r
1293 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
1294 It convers pointer to new virtual address.\r
1295\r
1296 @param[in] Event Event whose notification function is being invoked.\r
1297 @param[in] Context Pointer to the notification function's context.\r
1298\r
1299**/\r
1300VOID\r
1301EFIAPI\r
1302VariableAddressChangeEvent (\r
1303 IN EFI_EVENT Event,\r
1304 IN VOID *Context\r
1305 )\r
1306{\r
1307 EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
1308 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
aab3b9b9
MK
1309 EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeHobCacheBuffer);\r
1310 EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeNvCacheBuffer);\r
1311 EfiConvertPointer (EFI_OPTIONAL_PTR, (VOID **) &mVariableRuntimeVolatileCacheBuffer);\r
8a2d4996 1312}\r
1313\r
fa0737a8
SZ
1314/**\r
1315 This code gets variable payload size.\r
1316\r
1317 @param[out] VariablePayloadSize Output pointer to variable payload size.\r
1318\r
1319 @retval EFI_SUCCESS Get successfully.\r
1320 @retval Others Get unsuccessfully.\r
1321\r
1322**/\r
1323EFI_STATUS\r
1324EFIAPI\r
1325GetVariablePayloadSize (\r
1326 OUT UINTN *VariablePayloadSize\r
1327 )\r
1328{\r
1329 EFI_STATUS Status;\r
1330 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;\r
1331 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
1332 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
1333 UINTN CommSize;\r
1334 UINT8 *CommBuffer;\r
1335\r
1336 SmmGetPayloadSize = NULL;\r
1337 CommBuffer = NULL;\r
1338\r
1339 if(VariablePayloadSize == NULL) {\r
1340 return EFI_INVALID_PARAMETER;\r
1341 }\r
1342\r
1343 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
1344\r
1345 //\r
1346 // Init the communicate buffer. The buffer data size is:\r
1347 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
1348 //\r
1349 CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
1350 CommBuffer = AllocateZeroPool (CommSize);\r
1351 if (CommBuffer == NULL) {\r
1352 Status = EFI_OUT_OF_RESOURCES;\r
1353 goto Done;\r
1354 }\r
1355\r
1356 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
1357 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
1358 SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
1359\r
1360 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
1361 SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;\r
1362 SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;\r
1363\r
1364 //\r
1365 // Send data to SMM.\r
1366 //\r
1367 Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
1368 ASSERT_EFI_ERROR (Status);\r
1369\r
1370 Status = SmmVariableFunctionHeader->ReturnStatus;\r
1371 if (EFI_ERROR (Status)) {\r
1372 goto Done;\r
1373 }\r
1374\r
1375 //\r
1376 // Get data from SMM.\r
1377 //\r
1378 *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;\r
1379\r
1380Done:\r
1381 if (CommBuffer != NULL) {\r
1382 FreePool (CommBuffer);\r
1383 }\r
1384 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
1385 return Status;\r
1386}\r
8a2d4996 1387\r
aab3b9b9
MK
1388/**\r
1389 This code gets information needed from SMM for runtime cache initialization.\r
1390\r
1391 @param[out] TotalHobStorageSize Output pointer for the total HOB storage size in bytes.\r
1392 @param[out] TotalNvStorageSize Output pointer for the total non-volatile storage size in bytes.\r
1393 @param[out] TotalVolatileStorageSize Output pointer for the total volatile storage size in bytes.\r
1394 @param[out] AuthenticatedVariableUsage Output pointer that indicates if authenticated variables are to be used.\r
1395\r
1396 @retval EFI_SUCCESS Retrieved the size successfully.\r
1397 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.\r
1398 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.\r
1399 @retval Others Could not retrieve the size successfully.\r
1400\r
1401**/\r
1402EFI_STATUS\r
1403GetRuntimeCacheInfo (\r
1404 OUT UINTN *TotalHobStorageSize,\r
1405 OUT UINTN *TotalNvStorageSize,\r
1406 OUT UINTN *TotalVolatileStorageSize,\r
1407 OUT BOOLEAN *AuthenticatedVariableUsage\r
1408 )\r
1409{\r
1410 EFI_STATUS Status;\r
1411 SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *SmmGetRuntimeCacheInfo;\r
1412 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
1413 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
1414 UINTN CommSize;\r
1415 UINT8 *CommBuffer;\r
1416\r
1417 SmmGetRuntimeCacheInfo = NULL;\r
1418 CommBuffer = mVariableBuffer;\r
1419\r
1420 if (TotalHobStorageSize == NULL || TotalNvStorageSize == NULL || TotalVolatileStorageSize == NULL || AuthenticatedVariableUsage == NULL) {\r
1421 return EFI_INVALID_PARAMETER;\r
1422 }\r
1423\r
1424 if (CommBuffer == NULL) {\r
1425 return EFI_OUT_OF_RESOURCES;\r
1426 }\r
1427\r
1428 AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
1429\r
1430 CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);\r
1431 ZeroMem (CommBuffer, CommSize);\r
1432\r
1433 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
1434 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
1435 SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO);\r
1436\r
1437 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
1438 SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_RUNTIME_CACHE_INFO;\r
1439 SmmGetRuntimeCacheInfo = (SMM_VARIABLE_COMMUNICATE_GET_RUNTIME_CACHE_INFO *) SmmVariableFunctionHeader->Data;\r
1440\r
1441 //\r
1442 // Send data to SMM.\r
1443 //\r
1444 Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
1445 ASSERT_EFI_ERROR (Status);\r
1446 if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {\r
1447 Status = EFI_BAD_BUFFER_SIZE;\r
1448 goto Done;\r
1449 }\r
1450\r
1451 Status = SmmVariableFunctionHeader->ReturnStatus;\r
1452 if (EFI_ERROR (Status)) {\r
1453 goto Done;\r
1454 }\r
1455\r
1456 //\r
1457 // Get data from SMM.\r
1458 //\r
1459 *TotalHobStorageSize = SmmGetRuntimeCacheInfo->TotalHobStorageSize;\r
1460 *TotalNvStorageSize = SmmGetRuntimeCacheInfo->TotalNvStorageSize;\r
1461 *TotalVolatileStorageSize = SmmGetRuntimeCacheInfo->TotalVolatileStorageSize;\r
1462 *AuthenticatedVariableUsage = SmmGetRuntimeCacheInfo->AuthenticatedVariableUsage;\r
1463\r
1464Done:\r
1465 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
1466 return Status;\r
1467}\r
1468\r
1469/**\r
1470 Sends the runtime variable cache context information to SMM.\r
1471\r
1472 @retval EFI_SUCCESS Retrieved the size successfully.\r
1473 @retval EFI_INVALID_PARAMETER TotalNvStorageSize parameter is NULL.\r
1474 @retval EFI_OUT_OF_RESOURCES The memory resources needed for a CommBuffer are not available.\r
1475 @retval Others Could not retrieve the size successfully.;\r
1476\r
1477**/\r
1478EFI_STATUS\r
1479SendRuntimeVariableCacheContextToSmm (\r
1480 VOID\r
1481 )\r
1482{\r
1483 EFI_STATUS Status;\r
1484 SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *SmmRuntimeVarCacheContext;\r
1485 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
1486 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
1487 UINTN CommSize;\r
1488 UINT8 *CommBuffer;\r
1489\r
1490 SmmRuntimeVarCacheContext = NULL;\r
1491 CommBuffer = mVariableBuffer;\r
1492\r
1493 if (CommBuffer == NULL) {\r
1494 return EFI_OUT_OF_RESOURCES;\r
1495 }\r
1496\r
1497 AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
1498\r
1499 //\r
1500 // Init the communicate buffer. The buffer data size is:\r
1501 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
1502 //\r
1503 CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
1504 ZeroMem (CommBuffer, CommSize);\r
1505\r
1506 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
1507 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
1508 SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT);\r
1509\r
1510 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
1511 SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_INIT_RUNTIME_VARIABLE_CACHE_CONTEXT;\r
1512 SmmRuntimeVarCacheContext = (SMM_VARIABLE_COMMUNICATE_RUNTIME_VARIABLE_CACHE_CONTEXT *) SmmVariableFunctionHeader->Data;\r
1513\r
1514 SmmRuntimeVarCacheContext->RuntimeHobCache = mVariableRuntimeHobCacheBuffer;\r
1515 SmmRuntimeVarCacheContext->RuntimeVolatileCache = mVariableRuntimeVolatileCacheBuffer;\r
1516 SmmRuntimeVarCacheContext->RuntimeNvCache = mVariableRuntimeNvCacheBuffer;\r
1517 SmmRuntimeVarCacheContext->PendingUpdate = &mVariableRuntimeCachePendingUpdate;\r
1518 SmmRuntimeVarCacheContext->ReadLock = &mVariableRuntimeCacheReadLock;\r
1519 SmmRuntimeVarCacheContext->HobFlushComplete = &mHobFlushComplete;\r
1520\r
1521 //\r
1522 // Send data to SMM.\r
1523 //\r
1524 Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
1525 ASSERT_EFI_ERROR (Status);\r
1526 if (CommSize <= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE) {\r
1527 Status = EFI_BAD_BUFFER_SIZE;\r
1528 goto Done;\r
1529 }\r
1530\r
1531 Status = SmmVariableFunctionHeader->ReturnStatus;\r
1532 if (EFI_ERROR (Status)) {\r
1533 goto Done;\r
1534 }\r
1535\r
1536Done:\r
1537 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
1538 return Status;\r
1539}\r
1540\r
8a2d4996 1541/**\r
1542 Initialize variable service and install Variable Architectural protocol.\r
1543\r
1544 @param[in] Event Event whose notification function is being invoked.\r
1545 @param[in] Context Pointer to the notification function's context.\r
fa0737a8 1546\r
8a2d4996 1547**/\r
1548VOID\r
1549EFIAPI\r
1550SmmVariableReady (\r
1551 IN EFI_EVENT Event,\r
1552 IN VOID *Context\r
1553 )\r
1554{\r
1555 EFI_STATUS Status;\r
1556\r
aab3b9b9 1557 Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **) &mSmmVariable);\r
8a2d4996 1558 if (EFI_ERROR (Status)) {\r
1559 return;\r
1560 }\r
fa0737a8 1561\r
8a2d4996 1562 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
1563 ASSERT_EFI_ERROR (Status);\r
fa0737a8 1564\r
8a2d4996 1565 //\r
5e5bb2a9 1566 // Allocate memory for variable communicate buffer.\r
8a2d4996 1567 //\r
fa0737a8
SZ
1568 Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);\r
1569 ASSERT_EFI_ERROR (Status);\r
5e5bb2a9 1570 mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
8a2d4996 1571 mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);\r
1572 ASSERT (mVariableBuffer != NULL);\r
1573\r
1574 //\r
1575 // Save the buffer physical address used for SMM conmunication.\r
1576 //\r
1577 mVariableBufferPhysical = mVariableBuffer;\r
1578\r
aab3b9b9
MK
1579 if (FeaturePcdGet (PcdEnableVariableRuntimeCache)) {\r
1580 DEBUG ((DEBUG_INFO, "Variable driver runtime cache is enabled.\n"));\r
1581 //\r
1582 // Allocate runtime variable cache memory buffers.\r
1583 //\r
1584 Status = GetRuntimeCacheInfo (\r
1585 &mVariableRuntimeHobCacheBufferSize,\r
1586 &mVariableRuntimeNvCacheBufferSize,\r
1587 &mVariableRuntimeVolatileCacheBufferSize,\r
1588 &mVariableAuthFormat\r
1589 );\r
1590 if (!EFI_ERROR (Status)) {\r
1591 Status = InitVariableCache (&mVariableRuntimeHobCacheBuffer, &mVariableRuntimeHobCacheBufferSize);\r
1592 if (!EFI_ERROR (Status)) {\r
1593 Status = InitVariableCache (&mVariableRuntimeNvCacheBuffer, &mVariableRuntimeNvCacheBufferSize);\r
1594 if (!EFI_ERROR (Status)) {\r
1595 Status = InitVariableCache (&mVariableRuntimeVolatileCacheBuffer, &mVariableRuntimeVolatileCacheBufferSize);\r
1596 if (!EFI_ERROR (Status)) {\r
1597 Status = SendRuntimeVariableCacheContextToSmm ();\r
1598 if (!EFI_ERROR (Status)) {\r
1599 SyncRuntimeCache ();\r
1600 }\r
1601 }\r
1602 }\r
1603 }\r
1604 if (EFI_ERROR (Status)) {\r
1605 mVariableRuntimeHobCacheBuffer = NULL;\r
1606 mVariableRuntimeNvCacheBuffer = NULL;\r
1607 mVariableRuntimeVolatileCacheBuffer = NULL;\r
1608 }\r
1609 }\r
1610 ASSERT_EFI_ERROR (Status);\r
1611 } else {\r
1612 DEBUG ((DEBUG_INFO, "Variable driver runtime cache is disabled.\n"));\r
1613 }\r
1614\r
8a2d4996 1615 gRT->GetVariable = RuntimeServiceGetVariable;\r
1616 gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
1617 gRT->SetVariable = RuntimeServiceSetVariable;\r
1618 gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
fa0737a8 1619\r
8a2d4996 1620 //\r
1621 // Install the Variable Architectural Protocol on a new handle.\r
1622 //\r
1623 Status = gBS->InstallProtocolInterface (\r
1624 &mHandle,\r
fa0737a8 1625 &gEfiVariableArchProtocolGuid,\r
8a2d4996 1626 EFI_NATIVE_INTERFACE,\r
1627 NULL\r
1628 );\r
1629 ASSERT_EFI_ERROR (Status);\r
aa2868b3
SZ
1630\r
1631 mVariableLock.RequestToLock = VariableLockRequestToLock;\r
1632 Status = gBS->InstallMultipleProtocolInterfaces (\r
1633 &mHandle,\r
1634 &gEdkiiVariableLockProtocolGuid,\r
1635 &mVariableLock,\r
1636 NULL\r
1637 );\r
1638 ASSERT_EFI_ERROR (Status);\r
1639\r
1640 mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;\r
1641 mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;\r
1642 mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;\r
1643 Status = gBS->InstallMultipleProtocolInterfaces (\r
1644 &mHandle,\r
1645 &gEdkiiVarCheckProtocolGuid,\r
1646 &mVarCheck,\r
1647 NULL\r
1648 );\r
1649 ASSERT_EFI_ERROR (Status);\r
fa0737a8
SZ
1650\r
1651 gBS->CloseEvent (Event);\r
8a2d4996 1652}\r
1653\r
1654\r
1655/**\r
1656 SMM Non-Volatile variable write service is ready notify event handler.\r
1657\r
1658 @param[in] Event Event whose notification function is being invoked.\r
1659 @param[in] Context Pointer to the notification function's context.\r
fa0737a8 1660\r
8a2d4996 1661**/\r
1662VOID\r
1663EFIAPI\r
1664SmmVariableWriteReady (\r
1665 IN EFI_EVENT Event,\r
1666 IN VOID *Context\r
1667 )\r
1668{\r
1669 EFI_STATUS Status;\r
1670 VOID *ProtocolOps;\r
1671\r
1672 //\r
1673 // Check whether the protocol is installed or not.\r
1674 //\r
d00ed85e 1675 Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
8a2d4996 1676 if (EFI_ERROR (Status)) {\r
1677 return;\r
1678 }\r
fa0737a8 1679\r
dc9bd6ed
ZC
1680 //\r
1681 // Some Secure Boot Policy Var (SecureBoot, etc) updates following other\r
1682 // Secure Boot Policy Variable change. Record their initial value.\r
1683 //\r
1684 RecordSecureBootPolicyVarData();\r
1685\r
8a2d4996 1686 Status = gBS->InstallProtocolInterface (\r
1687 &mHandle,\r
fa0737a8 1688 &gEfiVariableWriteArchProtocolGuid,\r
8a2d4996 1689 EFI_NATIVE_INTERFACE,\r
1690 NULL\r
1691 );\r
fa0737a8
SZ
1692 ASSERT_EFI_ERROR (Status);\r
1693\r
1694 gBS->CloseEvent (Event);\r
8a2d4996 1695}\r
1696\r
1697\r
1698/**\r
1699 Variable Driver main entry point. The Variable driver places the 4 EFI\r
fa0737a8 1700 runtime services in the EFI System Table and installs arch protocols\r
d00ed85e 1701 for variable read and write services being available. It also registers\r
8a2d4996 1702 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
1703\r
fa0737a8 1704 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
8a2d4996 1705 @param[in] SystemTable A pointer to the EFI System Table.\r
fa0737a8 1706\r
8a2d4996 1707 @retval EFI_SUCCESS Variable service successfully initialized.\r
1708\r
1709**/\r
1710EFI_STATUS\r
1711EFIAPI\r
1712VariableSmmRuntimeInitialize (\r
1713 IN EFI_HANDLE ImageHandle,\r
1714 IN EFI_SYSTEM_TABLE *SystemTable\r
1715 )\r
1716{\r
1717 VOID *SmmVariableRegistration;\r
1718 VOID *SmmVariableWriteRegistration;\r
1719 EFI_EVENT OnReadyToBootEvent;\r
1720 EFI_EVENT ExitBootServiceEvent;\r
d3460bcb 1721 EFI_EVENT LegacyBootEvent;\r
6ed1ec59
SZ
1722\r
1723 EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\r
1724\r
8a2d4996 1725 //\r
1726 // Smm variable service is ready\r
1727 //\r
1728 EfiCreateProtocolNotifyEvent (\r
fa0737a8
SZ
1729 &gEfiSmmVariableProtocolGuid,\r
1730 TPL_CALLBACK,\r
1731 SmmVariableReady,\r
1732 NULL,\r
8a2d4996 1733 &SmmVariableRegistration\r
1734 );\r
1735\r
1736 //\r
1737 // Smm Non-Volatile variable write service is ready\r
1738 //\r
1739 EfiCreateProtocolNotifyEvent (\r
fa0737a8
SZ
1740 &gSmmVariableWriteGuid,\r
1741 TPL_CALLBACK,\r
1742 SmmVariableWriteReady,\r
1743 NULL,\r
8a2d4996 1744 &SmmVariableWriteRegistration\r
1745 );\r
1746\r
1747 //\r
1748 // Register the event to reclaim variable for OS usage.\r
1749 //\r
1750 EfiCreateEventReadyToBootEx (\r
fa0737a8
SZ
1751 TPL_NOTIFY,\r
1752 OnReadyToBoot,\r
1753 NULL,\r
8a2d4996 1754 &OnReadyToBootEvent\r
fa0737a8 1755 );\r
8a2d4996 1756\r
1757 //\r
1758 // Register the event to inform SMM variable that it is at runtime.\r
1759 //\r
1760 gBS->CreateEventEx (\r
1761 EVT_NOTIFY_SIGNAL,\r
1762 TPL_NOTIFY,\r
1763 OnExitBootServices,\r
1764 NULL,\r
1765 &gEfiEventExitBootServicesGuid,\r
1766 &ExitBootServiceEvent\r
fa0737a8 1767 );\r
8a2d4996 1768\r
d3460bcb
SZ
1769 //\r
1770 // Register the event to inform SMM variable that it is at runtime for legacy boot.\r
1771 // Reuse OnExitBootServices() here.\r
1772 //\r
1773 EfiCreateEventLegacyBootEx(\r
1774 TPL_NOTIFY,\r
1775 OnExitBootServices,\r
1776 NULL,\r
1777 &LegacyBootEvent\r
1778 );\r
1779\r
8a2d4996 1780 //\r
1781 // Register the event to convert the pointer for runtime.\r
1782 //\r
1783 gBS->CreateEventEx (\r
1784 EVT_NOTIFY_SIGNAL,\r
1785 TPL_NOTIFY,\r
1786 VariableAddressChangeEvent,\r
1787 NULL,\r
1788 &gEfiEventVirtualAddressChangeGuid,\r
1789 &mVirtualAddressChangeEvent\r
1790 );\r
fa0737a8 1791\r
8a2d4996 1792 return EFI_SUCCESS;\r
1793}\r
1794\r