]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
MdeModulePkg Variable: Abstract GetHobVariableStore function
[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
dc9bd6ed 16Copyright (c) 2010 - 2017, Intel Corporation. All rights reserved.<BR>\r
fa0737a8
SZ
17This program and the accompanying materials\r
18are licensed and made available under the terms and conditions of the BSD License\r
19which accompanies this distribution. The full text of the license may be found at\r
20http://opensource.org/licenses/bsd-license.php\r
8a2d4996 21\r
fa0737a8
SZ
22THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
23WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
8a2d4996 24\r
25**/\r
d00ed85e 26#include <PiDxe.h>\r
8a2d4996 27#include <Protocol/VariableWrite.h>\r
28#include <Protocol/Variable.h>\r
29#include <Protocol/SmmCommunication.h>\r
d00ed85e 30#include <Protocol/SmmVariable.h>\r
ff843847 31#include <Protocol/VariableLock.h>\r
efb01a10 32#include <Protocol/VarCheck.h>\r
8a2d4996 33\r
34#include <Library/UefiBootServicesTableLib.h>\r
35#include <Library/UefiRuntimeServicesTableLib.h>\r
36#include <Library/MemoryAllocationLib.h>\r
37#include <Library/UefiDriverEntryPoint.h>\r
38#include <Library/UefiRuntimeLib.h>\r
39#include <Library/BaseMemoryLib.h>\r
40#include <Library/DebugLib.h>\r
8a2d4996 41#include <Library/UefiLib.h>\r
42#include <Library/BaseLib.h>\r
43\r
44#include <Guid/EventGroup.h>\r
d00ed85e 45#include <Guid/SmmVariableCommon.h>\r
8a2d4996 46\r
00663d04
LE
47#include "PrivilegePolymorphic.h"\r
48\r
fa0737a8 49EFI_HANDLE mHandle = NULL;\r
8a2d4996 50EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;\r
51EFI_EVENT mVirtualAddressChangeEvent = NULL;\r
52EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;\r
53UINT8 *mVariableBuffer = NULL;\r
54UINT8 *mVariableBufferPhysical = NULL;\r
8a2d4996 55UINTN mVariableBufferSize;\r
5e5bb2a9 56UINTN mVariableBufferPayloadSize;\r
6ed1ec59 57EFI_LOCK mVariableServicesLock;\r
ff843847 58EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;\r
efb01a10 59EDKII_VAR_CHECK_PROTOCOL mVarCheck;\r
8a2d4996 60\r
dc9bd6ed
ZC
61/**\r
62 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).\r
63 Record their initial State when variable write service is ready.\r
64\r
65**/\r
66VOID\r
67EFIAPI\r
68RecordSecureBootPolicyVarData(\r
69 VOID\r
70 );\r
71\r
6ed1ec59
SZ
72/**\r
73 Acquires lock only at boot time. Simply returns at runtime.\r
74\r
75 This is a temperary function that will be removed when\r
76 EfiAcquireLock() in UefiLib can handle the call in UEFI\r
77 Runtimer driver in RT phase.\r
78 It calls EfiAcquireLock() at boot time, and simply returns\r
79 at runtime.\r
80\r
81 @param Lock A pointer to the lock to acquire.\r
82\r
83**/\r
84VOID\r
85AcquireLockOnlyAtBootTime (\r
86 IN EFI_LOCK *Lock\r
87 )\r
88{\r
89 if (!EfiAtRuntime ()) {\r
90 EfiAcquireLock (Lock);\r
91 }\r
92}\r
93\r
94/**\r
95 Releases lock only at boot time. Simply returns at runtime.\r
96\r
97 This is a temperary function which will be removed when\r
98 EfiReleaseLock() in UefiLib can handle the call in UEFI\r
99 Runtimer driver in RT phase.\r
100 It calls EfiReleaseLock() at boot time and simply returns\r
101 at runtime.\r
102\r
103 @param Lock A pointer to the lock to release.\r
104\r
105**/\r
106VOID\r
107ReleaseLockOnlyAtBootTime (\r
108 IN EFI_LOCK *Lock\r
109 )\r
110{\r
111 if (!EfiAtRuntime ()) {\r
112 EfiReleaseLock (Lock);\r
113 }\r
114}\r
8a2d4996 115\r
116/**\r
117 Initialize the communicate buffer using DataSize and Function.\r
118\r
119 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +\r
120 DataSize.\r
121\r
18a7dbbc
SZ
122 Caution: This function may receive untrusted input.\r
123 The data size external input, so this function will validate it carefully to avoid buffer overflow.\r
124\r
8a2d4996 125 @param[out] DataPtr Points to the data in the communicate buffer.\r
126 @param[in] DataSize The data size to send to SMM.\r
127 @param[in] Function The function number to initialize the communicate header.\r
fa0737a8 128\r
8a2d4996 129 @retval EFI_INVALID_PARAMETER The data size is too big.\r
130 @retval EFI_SUCCESS Find the specified variable.\r
131\r
132**/\r
133EFI_STATUS\r
134InitCommunicateBuffer (\r
135 OUT VOID **DataPtr OPTIONAL,\r
136 IN UINTN DataSize,\r
137 IN UINTN Function\r
138 )\r
139{\r
fa0737a8
SZ
140 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
141 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
142\r
8a2d4996 143\r
8a2d4996 144 if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {\r
145 return EFI_INVALID_PARAMETER;\r
146 }\r
147\r
148 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
149 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
150 SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
fa0737a8 151\r
8a2d4996 152 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
153 SmmVariableFunctionHeader->Function = Function;\r
154 if (DataPtr != NULL) {\r
155 *DataPtr = SmmVariableFunctionHeader->Data;\r
156 }\r
157\r
158 return EFI_SUCCESS;\r
159}\r
160\r
161\r
162/**\r
163 Send the data in communicate buffer to SMM.\r
164\r
165 @param[in] DataSize This size of the function header and the data.\r
166\r
32732a33 167 @retval EFI_SUCCESS Success is returned from the functin in SMM.\r
fa0737a8
SZ
168 @retval Others Failure is returned from the function in SMM.\r
169\r
8a2d4996 170**/\r
171EFI_STATUS\r
172SendCommunicateBuffer (\r
173 IN UINTN DataSize\r
174 )\r
175{\r
176 EFI_STATUS Status;\r
177 UINTN CommSize;\r
fa0737a8 178 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
8a2d4996 179 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
fa0737a8 180\r
8a2d4996 181 CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
182 Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);\r
183 ASSERT_EFI_ERROR (Status);\r
184\r
185 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
186 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
187 return SmmVariableFunctionHeader->ReturnStatus;\r
188}\r
189\r
ff843847
RN
190/**\r
191 Mark a variable that will become read-only after leaving the DXE phase of execution.\r
192\r
193 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.\r
194 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.\r
195 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.\r
196\r
197 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked\r
198 as pending to be read-only.\r
199 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.\r
200 Or VariableName is an empty string.\r
201 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
202 already been signaled.\r
203 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.\r
204**/\r
205EFI_STATUS\r
206EFIAPI\r
207VariableLockRequestToLock (\r
208 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
209 IN CHAR16 *VariableName,\r
210 IN EFI_GUID *VendorGuid\r
211 )\r
212{\r
213 EFI_STATUS Status;\r
51547bb8 214 UINTN VariableNameSize;\r
ff843847
RN
215 UINTN PayloadSize;\r
216 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE *VariableToLock;\r
217\r
218 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
219 return EFI_INVALID_PARAMETER;\r
220 }\r
221\r
51547bb8 222 VariableNameSize = StrSize (VariableName);\r
4e1005ec 223 VariableToLock = NULL;\r
51547bb8
RN
224\r
225 //\r
226 // If VariableName exceeds SMM payload limit. Return failure\r
227 //\r
228 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {\r
229 return EFI_INVALID_PARAMETER;\r
230 }\r
231\r
ff843847
RN
232 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
233\r
234 //\r
235 // Init the communicate buffer. The buffer data size is:\r
236 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
237 //\r
51547bb8 238 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;\r
ff843847
RN
239 Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);\r
240 if (EFI_ERROR (Status)) {\r
241 goto Done;\r
242 }\r
243 ASSERT (VariableToLock != NULL);\r
244\r
245 CopyGuid (&VariableToLock->Guid, VendorGuid);\r
51547bb8 246 VariableToLock->NameSize = VariableNameSize;\r
ff843847
RN
247 CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);\r
248\r
249 //\r
250 // Send data to SMM.\r
251 //\r
252 Status = SendCommunicateBuffer (PayloadSize);\r
253\r
254Done:\r
255 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
256 return Status;\r
257}\r
8a2d4996 258\r
efb01a10
SZ
259/**\r
260 Register SetVariable check handler.\r
261\r
262 @param[in] Handler Pointer to check handler.\r
263\r
264 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.\r
265 @retval EFI_INVALID_PARAMETER Handler is NULL.\r
266 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
267 already been signaled.\r
268 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.\r
269 @retval EFI_UNSUPPORTED This interface is not implemented.\r
270 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.\r
271\r
272**/\r
273EFI_STATUS\r
274EFIAPI\r
275VarCheckRegisterSetVariableCheckHandler (\r
276 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler\r
277 )\r
278{\r
279 return EFI_UNSUPPORTED;\r
280}\r
281\r
282/**\r
283 Variable property set.\r
284\r
285 @param[in] Name Pointer to the variable name.\r
286 @param[in] Guid Pointer to the vendor GUID.\r
287 @param[in] VariableProperty Pointer to the input variable property.\r
288\r
289 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.\r
290 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,\r
291 or the fields of VariableProperty are not valid.\r
292 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
293 already been signaled.\r
294 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.\r
295\r
296**/\r
297EFI_STATUS\r
298EFIAPI\r
299VarCheckVariablePropertySet (\r
300 IN CHAR16 *Name,\r
301 IN EFI_GUID *Guid,\r
302 IN VAR_CHECK_VARIABLE_PROPERTY *VariableProperty\r
303 )\r
304{\r
305 EFI_STATUS Status;\r
306 UINTN VariableNameSize;\r
307 UINTN PayloadSize;\r
308 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
309\r
310 if (Name == NULL || Name[0] == 0 || Guid == NULL) {\r
311 return EFI_INVALID_PARAMETER;\r
312 }\r
313\r
314 if (VariableProperty == NULL) {\r
315 return EFI_INVALID_PARAMETER;\r
316 }\r
317\r
318 if (VariableProperty->Revision != VAR_CHECK_VARIABLE_PROPERTY_REVISION) {\r
319 return EFI_INVALID_PARAMETER;\r
320 }\r
321\r
322 VariableNameSize = StrSize (Name);\r
323 CommVariableProperty = NULL;\r
324\r
325 //\r
326 // If VariableName exceeds SMM payload limit. Return failure\r
327 //\r
328 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {\r
329 return EFI_INVALID_PARAMETER;\r
330 }\r
331\r
332 AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
333\r
334 //\r
335 // Init the communicate buffer. The buffer data size is:\r
336 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
337 //\r
338 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;\r
339 Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET);\r
340 if (EFI_ERROR (Status)) {\r
341 goto Done;\r
342 }\r
343 ASSERT (CommVariableProperty != NULL);\r
344\r
345 CopyGuid (&CommVariableProperty->Guid, Guid);\r
346 CopyMem (&CommVariableProperty->VariableProperty, VariableProperty, sizeof (*VariableProperty));\r
347 CommVariableProperty->NameSize = VariableNameSize;\r
348 CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);\r
349\r
350 //\r
351 // Send data to SMM.\r
352 //\r
353 Status = SendCommunicateBuffer (PayloadSize);\r
354\r
355Done:\r
356 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
357 return Status;\r
358}\r
359\r
360/**\r
361 Variable property get.\r
362\r
363 @param[in] Name Pointer to the variable name.\r
364 @param[in] Guid Pointer to the vendor GUID.\r
365 @param[out] VariableProperty Pointer to the output variable property.\r
366\r
367 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.\r
368 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.\r
369 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.\r
370\r
371**/\r
372EFI_STATUS\r
373EFIAPI\r
374VarCheckVariablePropertyGet (\r
375 IN CHAR16 *Name,\r
376 IN EFI_GUID *Guid,\r
377 OUT VAR_CHECK_VARIABLE_PROPERTY *VariableProperty\r
378 )\r
379{\r
380 EFI_STATUS Status;\r
381 UINTN VariableNameSize;\r
382 UINTN PayloadSize;\r
383 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY *CommVariableProperty;\r
384\r
385 if (Name == NULL || Name[0] == 0 || Guid == NULL) {\r
386 return EFI_INVALID_PARAMETER;\r
387 }\r
388\r
389 if (VariableProperty == NULL) {\r
390 return EFI_INVALID_PARAMETER;\r
391 }\r
392\r
393 VariableNameSize = StrSize (Name);\r
394 CommVariableProperty = NULL;\r
395\r
396 //\r
397 // If VariableName exceeds SMM payload limit. Return failure\r
398 //\r
399 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name)) {\r
400 return EFI_INVALID_PARAMETER;\r
401 }\r
402\r
403 AcquireLockOnlyAtBootTime (&mVariableServicesLock);\r
404\r
405 //\r
406 // Init the communicate buffer. The buffer data size is:\r
407 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
408 //\r
409 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY, Name) + VariableNameSize;\r
410 Status = InitCommunicateBuffer ((VOID **) &CommVariableProperty, PayloadSize, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET);\r
411 if (EFI_ERROR (Status)) {\r
412 goto Done;\r
413 }\r
414 ASSERT (CommVariableProperty != NULL);\r
415\r
416 CopyGuid (&CommVariableProperty->Guid, Guid);\r
417 CommVariableProperty->NameSize = VariableNameSize;\r
418 CopyMem (CommVariableProperty->Name, Name, CommVariableProperty->NameSize);\r
419\r
420 //\r
421 // Send data to SMM.\r
422 //\r
423 Status = SendCommunicateBuffer (PayloadSize);\r
424 if (Status == EFI_SUCCESS) {\r
425 CopyMem (VariableProperty, &CommVariableProperty->VariableProperty, sizeof (*VariableProperty));\r
426 }\r
427\r
428Done:\r
429 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
430 return Status;\r
431}\r
432\r
8a2d4996 433/**\r
434 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
435\r
18a7dbbc
SZ
436 Caution: This function may receive untrusted input.\r
437 The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
438\r
8a2d4996 439 @param[in] VariableName Name of Variable to be found.\r
440 @param[in] VendorGuid Variable vendor GUID.\r
441 @param[out] Attributes Attribute value of the variable found.\r
442 @param[in, out] DataSize Size of Data found. If size is less than the\r
443 data, this value contains the required size.\r
444 @param[out] Data Data pointer.\r
fa0737a8 445\r
8a2d4996 446 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
447 @retval EFI_SUCCESS Find the specified variable.\r
448 @retval EFI_NOT_FOUND Not found.\r
449 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
450\r
451**/\r
452EFI_STATUS\r
453EFIAPI\r
454RuntimeServiceGetVariable (\r
455 IN CHAR16 *VariableName,\r
456 IN EFI_GUID *VendorGuid,\r
457 OUT UINT32 *Attributes OPTIONAL,\r
458 IN OUT UINTN *DataSize,\r
459 OUT VOID *Data\r
460 )\r
461{\r
462 EFI_STATUS Status;\r
463 UINTN PayloadSize;\r
464 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
3a146f2a 465 UINTN TempDataSize;\r
9d00d20e 466 UINTN VariableNameSize;\r
8a2d4996 467\r
468 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
469 return EFI_INVALID_PARAMETER;\r
470 }\r
471\r
3a146f2a 472 TempDataSize = *DataSize;\r
9d00d20e 473 VariableNameSize = StrSize (VariableName);\r
4e1005ec 474 SmmVariableHeader = NULL;\r
3a146f2a 475\r
476 //\r
477 // If VariableName exceeds SMM payload limit. Return failure\r
478 //\r
5e5bb2a9 479 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
3588bb35
SZ
480 return EFI_INVALID_PARAMETER;\r
481 }\r
482\r
6ed1ec59
SZ
483 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
484\r
8a2d4996 485 //\r
486 // Init the communicate buffer. The buffer data size is:\r
6ed1ec59 487 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
8a2d4996 488 //\r
5e5bb2a9 489 if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {\r
3a146f2a 490 //\r
491 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
492 //\r
5e5bb2a9 493 TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;\r
3a146f2a 494 }\r
9d00d20e 495 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
3a146f2a 496\r
5c7fa429 497 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
8a2d4996 498 if (EFI_ERROR (Status)) {\r
6ed1ec59 499 goto Done;\r
8a2d4996 500 }\r
501 ASSERT (SmmVariableHeader != NULL);\r
502\r
503 CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
3a146f2a 504 SmmVariableHeader->DataSize = TempDataSize;\r
9d00d20e 505 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 506 if (Attributes == NULL) {\r
507 SmmVariableHeader->Attributes = 0;\r
508 } else {\r
509 SmmVariableHeader->Attributes = *Attributes;\r
510 }\r
511 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
512\r
513 //\r
514 // Send data to SMM.\r
515 //\r
516 Status = SendCommunicateBuffer (PayloadSize);\r
517\r
518 //\r
519 // Get data from SMM.\r
520 //\r
3a146f2a 521 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
522 //\r
523 // SMM CommBuffer DataSize can be a trimed value\r
524 // Only update DataSize when needed\r
525 //\r
526 *DataSize = SmmVariableHeader->DataSize;\r
527 }\r
8a2d4996 528 if (Attributes != NULL) {\r
529 *Attributes = SmmVariableHeader->Attributes;\r
530 }\r
531\r
532 if (EFI_ERROR (Status)) {\r
6ed1ec59 533 goto Done;\r
8a2d4996 534 }\r
535\r
82e47eb2
SZ
536 if (Data != NULL) {\r
537 CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
538 } else {\r
539 Status = EFI_INVALID_PARAMETER;\r
540 }\r
8a2d4996 541\r
6ed1ec59
SZ
542Done:\r
543 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 544 return Status;\r
545}\r
546\r
547\r
548/**\r
549 This code Finds the Next available variable.\r
550\r
551 @param[in, out] VariableNameSize Size of the variable name.\r
552 @param[in, out] VariableName Pointer to variable name.\r
553 @param[in, out] VendorGuid Variable Vendor Guid.\r
554\r
555 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
556 @retval EFI_SUCCESS Find the specified variable.\r
557 @retval EFI_NOT_FOUND Not found.\r
558 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
559\r
560**/\r
561EFI_STATUS\r
562EFIAPI\r
563RuntimeServiceGetNextVariableName (\r
564 IN OUT UINTN *VariableNameSize,\r
565 IN OUT CHAR16 *VariableName,\r
566 IN OUT EFI_GUID *VendorGuid\r
567 )\r
568{\r
569 EFI_STATUS Status;\r
570 UINTN PayloadSize;\r
571 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
9d00d20e
SZ
572 UINTN OutVariableNameSize;\r
573 UINTN InVariableNameSize;\r
8a2d4996 574\r
575 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
576 return EFI_INVALID_PARAMETER;\r
577 }\r
6ed1ec59 578\r
9d00d20e
SZ
579 OutVariableNameSize = *VariableNameSize;\r
580 InVariableNameSize = StrSize (VariableName);\r
4e1005ec 581 SmmGetNextVariableName = NULL;\r
0c55190f 582\r
583 //\r
584 // If input string exceeds SMM payload limit. Return failure\r
585 //\r
5e5bb2a9 586 if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
3588bb35
SZ
587 return EFI_INVALID_PARAMETER;\r
588 }\r
589\r
6ed1ec59
SZ
590 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
591\r
8a2d4996 592 //\r
593 // Init the communicate buffer. The buffer data size is:\r
594 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
595 //\r
5e5bb2a9 596 if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
0c55190f 597 //\r
598 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
599 //\r
5e5bb2a9 600 OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
0c55190f 601 }\r
602 //\r
603 // Payload should be Guid + NameSize + MAX of Input & Output buffer\r
604 //\r
9d00d20e 605 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);\r
0c55190f 606\r
5c7fa429 607 Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
8a2d4996 608 if (EFI_ERROR (Status)) {\r
6ed1ec59 609 goto Done;\r
8a2d4996 610 }\r
611 ASSERT (SmmGetNextVariableName != NULL);\r
612\r
0c55190f 613 //\r
614 // SMM comm buffer->NameSize is buffer size for return string\r
615 //\r
9d00d20e 616 SmmGetNextVariableName->NameSize = OutVariableNameSize;\r
0c55190f 617\r
8a2d4996 618 CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
0c55190f 619 //\r
620 // Copy whole string\r
621 //\r
9d00d20e
SZ
622 CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);\r
623 if (OutVariableNameSize > InVariableNameSize) {\r
624 ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
625 }\r
8a2d4996 626\r
627 //\r
628 // Send data to SMM\r
629 //\r
630 Status = SendCommunicateBuffer (PayloadSize);\r
631\r
632 //\r
633 // Get data from SMM.\r
634 //\r
9d00d20e
SZ
635 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
636 //\r
637 // SMM CommBuffer NameSize can be a trimed value\r
638 // Only update VariableNameSize when needed\r
639 //\r
640 *VariableNameSize = SmmGetNextVariableName->NameSize;\r
641 }\r
8a2d4996 642 if (EFI_ERROR (Status)) {\r
6ed1ec59 643 goto Done;\r
8a2d4996 644 }\r
fa0737a8 645\r
8a2d4996 646 CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
fa0737a8 647 CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);\r
8a2d4996 648\r
6ed1ec59
SZ
649Done:\r
650 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 651 return Status;\r
652}\r
653\r
654/**\r
655 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
656\r
18a7dbbc
SZ
657 Caution: This function may receive untrusted input.\r
658 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.\r
659\r
8a2d4996 660 @param[in] VariableName Name of Variable to be found.\r
661 @param[in] VendorGuid Variable vendor GUID.\r
662 @param[in] Attributes Attribute value of the variable found\r
663 @param[in] DataSize Size of Data found. If size is less than the\r
664 data, this value contains the required size.\r
665 @param[in] Data Data pointer.\r
666\r
667 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
668 @retval EFI_SUCCESS Set successfully.\r
669 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
670 @retval EFI_NOT_FOUND Not found.\r
671 @retval EFI_WRITE_PROTECTED Variable is read-only.\r
672\r
673**/\r
674EFI_STATUS\r
675EFIAPI\r
676RuntimeServiceSetVariable (\r
677 IN CHAR16 *VariableName,\r
678 IN EFI_GUID *VendorGuid,\r
679 IN UINT32 Attributes,\r
680 IN UINTN DataSize,\r
681 IN VOID *Data\r
682 )\r
683{\r
684 EFI_STATUS Status;\r
fa0737a8 685 UINTN PayloadSize;\r
8a2d4996 686 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
9d00d20e 687 UINTN VariableNameSize;\r
fa0737a8 688\r
8a2d4996 689 //\r
690 // Check input parameters.\r
691 //\r
692 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
693 return EFI_INVALID_PARAMETER;\r
fa0737a8 694 }\r
8a2d4996 695\r
696 if (DataSize != 0 && Data == NULL) {\r
697 return EFI_INVALID_PARAMETER;\r
698 }\r
6ed1ec59 699\r
9d00d20e 700 VariableNameSize = StrSize (VariableName);\r
4e1005ec 701 SmmVariableHeader = NULL;\r
3588bb35 702\r
5e5bb2a9
SZ
703 //\r
704 // If VariableName or DataSize exceeds SMM payload limit. Return failure\r
705 //\r
706 if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
707 (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){\r
56251c66 708 return EFI_INVALID_PARAMETER;\r
709 }\r
710\r
6ed1ec59 711 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
fa0737a8 712\r
8a2d4996 713 //\r
714 // Init the communicate buffer. The buffer data size is:\r
715 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
716 //\r
9d00d20e 717 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;\r
5c7fa429 718 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
8a2d4996 719 if (EFI_ERROR (Status)) {\r
6ed1ec59 720 goto Done;\r
8a2d4996 721 }\r
722 ASSERT (SmmVariableHeader != NULL);\r
723\r
724 CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
725 SmmVariableHeader->DataSize = DataSize;\r
9d00d20e 726 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 727 SmmVariableHeader->Attributes = Attributes;\r
728 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
729 CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
730\r
731 //\r
732 // Send data to SMM.\r
733 //\r
734 Status = SendCommunicateBuffer (PayloadSize);\r
6ed1ec59
SZ
735\r
736Done:\r
737 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
fa0737a8
SZ
738\r
739 if (!EfiAtRuntime ()) {\r
740 if (!EFI_ERROR (Status)) {\r
741 SecureBootHook (\r
742 VariableName,\r
743 VendorGuid\r
744 );\r
745 }\r
746 }\r
8a2d4996 747 return Status;\r
748}\r
749\r
750\r
751/**\r
752 This code returns information about the EFI variables.\r
753\r
754 @param[in] Attributes Attributes bitmask to specify the type of variables\r
755 on which to return information.\r
756 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
757 for the EFI variables associated with the attributes specified.\r
758 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
759 for EFI variables associated with the attributes specified.\r
760 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
761 associated with the attributes specified.\r
762\r
763 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
764 @retval EFI_SUCCESS Query successfully.\r
765 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.\r
766\r
767**/\r
768EFI_STATUS\r
769EFIAPI\r
770RuntimeServiceQueryVariableInfo (\r
771 IN UINT32 Attributes,\r
772 OUT UINT64 *MaximumVariableStorageSize,\r
773 OUT UINT64 *RemainingVariableStorageSize,\r
774 OUT UINT64 *MaximumVariableSize\r
775 )\r
776{\r
777 EFI_STATUS Status;\r
778 UINTN PayloadSize;\r
779 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
780\r
4e1005ec
ED
781 SmmQueryVariableInfo = NULL;\r
782\r
8a2d4996 783 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
784 return EFI_INVALID_PARAMETER;\r
785 }\r
6ed1ec59
SZ
786\r
787 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
788\r
8a2d4996 789 //\r
790 // Init the communicate buffer. The buffer data size is:\r
791 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
792 //\r
d00ed85e 793 PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
5c7fa429 794 Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
8a2d4996 795 if (EFI_ERROR (Status)) {\r
6ed1ec59 796 goto Done;\r
8a2d4996 797 }\r
798 ASSERT (SmmQueryVariableInfo != NULL);\r
799\r
800 SmmQueryVariableInfo->Attributes = Attributes;\r
801\r
802 //\r
803 // Send data to SMM.\r
804 //\r
805 Status = SendCommunicateBuffer (PayloadSize);\r
806 if (EFI_ERROR (Status)) {\r
6ed1ec59 807 goto Done;\r
8a2d4996 808 }\r
809\r
810 //\r
811 // Get data from SMM.\r
812 //\r
813 *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;\r
814 *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
fa0737a8 815 *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;\r
6ed1ec59
SZ
816\r
817Done:\r
818 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
aab9212f 819 return Status;\r
8a2d4996 820}\r
821\r
822\r
823/**\r
824 Exit Boot Services Event notification handler.\r
825\r
826 Notify SMM variable driver about the event.\r
827\r
828 @param[in] Event Event whose notification function is being invoked.\r
829 @param[in] Context Pointer to the notification function's context.\r
830\r
831**/\r
832VOID\r
833EFIAPI\r
834OnExitBootServices (\r
835 IN EFI_EVENT Event,\r
836 IN VOID *Context\r
837 )\r
838{\r
839 //\r
840 // Init the communicate buffer. The buffer data size is:\r
841 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
842 //\r
fa0737a8 843 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);\r
8a2d4996 844\r
845 //\r
846 // Send data to SMM.\r
847 //\r
848 SendCommunicateBuffer (0);\r
849}\r
850\r
851\r
852/**\r
853 On Ready To Boot Services Event notification handler.\r
854\r
855 Notify SMM variable driver about the event.\r
856\r
857 @param[in] Event Event whose notification function is being invoked\r
858 @param[in] Context Pointer to the notification function's context\r
859\r
860**/\r
861VOID\r
862EFIAPI\r
863OnReadyToBoot (\r
864 IN EFI_EVENT Event,\r
865 IN VOID *Context\r
866 )\r
867{\r
868 //\r
869 // Init the communicate buffer. The buffer data size is:\r
870 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
871 //\r
872 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
fa0737a8 873\r
8a2d4996 874 //\r
875 // Send data to SMM.\r
876 //\r
877 SendCommunicateBuffer (0);\r
fa0737a8
SZ
878\r
879 gBS->CloseEvent (Event);\r
8a2d4996 880}\r
881\r
882\r
883/**\r
884 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
885\r
886 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
887 It convers pointer to new virtual address.\r
888\r
889 @param[in] Event Event whose notification function is being invoked.\r
890 @param[in] Context Pointer to the notification function's context.\r
891\r
892**/\r
893VOID\r
894EFIAPI\r
895VariableAddressChangeEvent (\r
896 IN EFI_EVENT Event,\r
897 IN VOID *Context\r
898 )\r
899{\r
900 EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
901 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
902}\r
903\r
fa0737a8
SZ
904/**\r
905 This code gets variable payload size.\r
906\r
907 @param[out] VariablePayloadSize Output pointer to variable payload size.\r
908\r
909 @retval EFI_SUCCESS Get successfully.\r
910 @retval Others Get unsuccessfully.\r
911\r
912**/\r
913EFI_STATUS\r
914EFIAPI\r
915GetVariablePayloadSize (\r
916 OUT UINTN *VariablePayloadSize\r
917 )\r
918{\r
919 EFI_STATUS Status;\r
920 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *SmmGetPayloadSize;\r
921 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader;\r
922 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
923 UINTN CommSize;\r
924 UINT8 *CommBuffer;\r
925\r
926 SmmGetPayloadSize = NULL;\r
927 CommBuffer = NULL;\r
928\r
929 if(VariablePayloadSize == NULL) {\r
930 return EFI_INVALID_PARAMETER;\r
931 }\r
932\r
933 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
934\r
935 //\r
936 // Init the communicate buffer. The buffer data size is:\r
937 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
938 //\r
939 CommSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
940 CommBuffer = AllocateZeroPool (CommSize);\r
941 if (CommBuffer == NULL) {\r
942 Status = EFI_OUT_OF_RESOURCES;\r
943 goto Done;\r
944 }\r
945\r
946 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) CommBuffer;\r
947 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
948 SmmCommunicateHeader->MessageLength = SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);\r
949\r
950 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
951 SmmVariableFunctionHeader->Function = SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE;\r
952 SmmGetPayloadSize = (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE *) SmmVariableFunctionHeader->Data;\r
953\r
954 //\r
955 // Send data to SMM.\r
956 //\r
957 Status = mSmmCommunication->Communicate (mSmmCommunication, CommBuffer, &CommSize);\r
958 ASSERT_EFI_ERROR (Status);\r
959\r
960 Status = SmmVariableFunctionHeader->ReturnStatus;\r
961 if (EFI_ERROR (Status)) {\r
962 goto Done;\r
963 }\r
964\r
965 //\r
966 // Get data from SMM.\r
967 //\r
968 *VariablePayloadSize = SmmGetPayloadSize->VariablePayloadSize;\r
969\r
970Done:\r
971 if (CommBuffer != NULL) {\r
972 FreePool (CommBuffer);\r
973 }\r
974 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
975 return Status;\r
976}\r
8a2d4996 977\r
978/**\r
979 Initialize variable service and install Variable Architectural protocol.\r
980\r
981 @param[in] Event Event whose notification function is being invoked.\r
982 @param[in] Context Pointer to the notification function's context.\r
fa0737a8 983\r
8a2d4996 984**/\r
985VOID\r
986EFIAPI\r
987SmmVariableReady (\r
988 IN EFI_EVENT Event,\r
989 IN VOID *Context\r
990 )\r
991{\r
992 EFI_STATUS Status;\r
993\r
994 Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r
995 if (EFI_ERROR (Status)) {\r
996 return;\r
997 }\r
fa0737a8 998\r
8a2d4996 999 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
1000 ASSERT_EFI_ERROR (Status);\r
fa0737a8 1001\r
8a2d4996 1002 //\r
5e5bb2a9 1003 // Allocate memory for variable communicate buffer.\r
8a2d4996 1004 //\r
fa0737a8
SZ
1005 Status = GetVariablePayloadSize (&mVariableBufferPayloadSize);\r
1006 ASSERT_EFI_ERROR (Status);\r
5e5bb2a9 1007 mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
8a2d4996 1008 mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);\r
1009 ASSERT (mVariableBuffer != NULL);\r
1010\r
1011 //\r
1012 // Save the buffer physical address used for SMM conmunication.\r
1013 //\r
1014 mVariableBufferPhysical = mVariableBuffer;\r
1015\r
1016 gRT->GetVariable = RuntimeServiceGetVariable;\r
1017 gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
1018 gRT->SetVariable = RuntimeServiceSetVariable;\r
1019 gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
fa0737a8 1020\r
8a2d4996 1021 //\r
1022 // Install the Variable Architectural Protocol on a new handle.\r
1023 //\r
1024 Status = gBS->InstallProtocolInterface (\r
1025 &mHandle,\r
fa0737a8 1026 &gEfiVariableArchProtocolGuid,\r
8a2d4996 1027 EFI_NATIVE_INTERFACE,\r
1028 NULL\r
1029 );\r
1030 ASSERT_EFI_ERROR (Status);\r
aa2868b3
SZ
1031\r
1032 mVariableLock.RequestToLock = VariableLockRequestToLock;\r
1033 Status = gBS->InstallMultipleProtocolInterfaces (\r
1034 &mHandle,\r
1035 &gEdkiiVariableLockProtocolGuid,\r
1036 &mVariableLock,\r
1037 NULL\r
1038 );\r
1039 ASSERT_EFI_ERROR (Status);\r
1040\r
1041 mVarCheck.RegisterSetVariableCheckHandler = VarCheckRegisterSetVariableCheckHandler;\r
1042 mVarCheck.VariablePropertySet = VarCheckVariablePropertySet;\r
1043 mVarCheck.VariablePropertyGet = VarCheckVariablePropertyGet;\r
1044 Status = gBS->InstallMultipleProtocolInterfaces (\r
1045 &mHandle,\r
1046 &gEdkiiVarCheckProtocolGuid,\r
1047 &mVarCheck,\r
1048 NULL\r
1049 );\r
1050 ASSERT_EFI_ERROR (Status);\r
fa0737a8
SZ
1051\r
1052 gBS->CloseEvent (Event);\r
8a2d4996 1053}\r
1054\r
1055\r
1056/**\r
1057 SMM Non-Volatile variable write service is ready notify event handler.\r
1058\r
1059 @param[in] Event Event whose notification function is being invoked.\r
1060 @param[in] Context Pointer to the notification function's context.\r
fa0737a8 1061\r
8a2d4996 1062**/\r
1063VOID\r
1064EFIAPI\r
1065SmmVariableWriteReady (\r
1066 IN EFI_EVENT Event,\r
1067 IN VOID *Context\r
1068 )\r
1069{\r
1070 EFI_STATUS Status;\r
1071 VOID *ProtocolOps;\r
1072\r
1073 //\r
1074 // Check whether the protocol is installed or not.\r
1075 //\r
d00ed85e 1076 Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
8a2d4996 1077 if (EFI_ERROR (Status)) {\r
1078 return;\r
1079 }\r
fa0737a8 1080\r
dc9bd6ed
ZC
1081 //\r
1082 // Some Secure Boot Policy Var (SecureBoot, etc) updates following other\r
1083 // Secure Boot Policy Variable change. Record their initial value.\r
1084 //\r
1085 RecordSecureBootPolicyVarData();\r
1086\r
8a2d4996 1087 Status = gBS->InstallProtocolInterface (\r
1088 &mHandle,\r
fa0737a8 1089 &gEfiVariableWriteArchProtocolGuid,\r
8a2d4996 1090 EFI_NATIVE_INTERFACE,\r
1091 NULL\r
1092 );\r
fa0737a8
SZ
1093 ASSERT_EFI_ERROR (Status);\r
1094\r
1095 gBS->CloseEvent (Event);\r
8a2d4996 1096}\r
1097\r
1098\r
1099/**\r
1100 Variable Driver main entry point. The Variable driver places the 4 EFI\r
fa0737a8 1101 runtime services in the EFI System Table and installs arch protocols\r
d00ed85e 1102 for variable read and write services being available. It also registers\r
8a2d4996 1103 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
1104\r
fa0737a8 1105 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
8a2d4996 1106 @param[in] SystemTable A pointer to the EFI System Table.\r
fa0737a8 1107\r
8a2d4996 1108 @retval EFI_SUCCESS Variable service successfully initialized.\r
1109\r
1110**/\r
1111EFI_STATUS\r
1112EFIAPI\r
1113VariableSmmRuntimeInitialize (\r
1114 IN EFI_HANDLE ImageHandle,\r
1115 IN EFI_SYSTEM_TABLE *SystemTable\r
1116 )\r
1117{\r
1118 VOID *SmmVariableRegistration;\r
1119 VOID *SmmVariableWriteRegistration;\r
1120 EFI_EVENT OnReadyToBootEvent;\r
1121 EFI_EVENT ExitBootServiceEvent;\r
d3460bcb 1122 EFI_EVENT LegacyBootEvent;\r
6ed1ec59
SZ
1123\r
1124 EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\r
1125\r
8a2d4996 1126 //\r
1127 // Smm variable service is ready\r
1128 //\r
1129 EfiCreateProtocolNotifyEvent (\r
fa0737a8
SZ
1130 &gEfiSmmVariableProtocolGuid,\r
1131 TPL_CALLBACK,\r
1132 SmmVariableReady,\r
1133 NULL,\r
8a2d4996 1134 &SmmVariableRegistration\r
1135 );\r
1136\r
1137 //\r
1138 // Smm Non-Volatile variable write service is ready\r
1139 //\r
1140 EfiCreateProtocolNotifyEvent (\r
fa0737a8
SZ
1141 &gSmmVariableWriteGuid,\r
1142 TPL_CALLBACK,\r
1143 SmmVariableWriteReady,\r
1144 NULL,\r
8a2d4996 1145 &SmmVariableWriteRegistration\r
1146 );\r
1147\r
1148 //\r
1149 // Register the event to reclaim variable for OS usage.\r
1150 //\r
1151 EfiCreateEventReadyToBootEx (\r
fa0737a8
SZ
1152 TPL_NOTIFY,\r
1153 OnReadyToBoot,\r
1154 NULL,\r
8a2d4996 1155 &OnReadyToBootEvent\r
fa0737a8 1156 );\r
8a2d4996 1157\r
1158 //\r
1159 // Register the event to inform SMM variable that it is at runtime.\r
1160 //\r
1161 gBS->CreateEventEx (\r
1162 EVT_NOTIFY_SIGNAL,\r
1163 TPL_NOTIFY,\r
1164 OnExitBootServices,\r
1165 NULL,\r
1166 &gEfiEventExitBootServicesGuid,\r
1167 &ExitBootServiceEvent\r
fa0737a8 1168 );\r
8a2d4996 1169\r
d3460bcb
SZ
1170 //\r
1171 // Register the event to inform SMM variable that it is at runtime for legacy boot.\r
1172 // Reuse OnExitBootServices() here.\r
1173 //\r
1174 EfiCreateEventLegacyBootEx(\r
1175 TPL_NOTIFY,\r
1176 OnExitBootServices,\r
1177 NULL,\r
1178 &LegacyBootEvent\r
1179 );\r
1180\r
8a2d4996 1181 //\r
1182 // Register the event to convert the pointer for runtime.\r
1183 //\r
1184 gBS->CreateEventEx (\r
1185 EVT_NOTIFY_SIGNAL,\r
1186 TPL_NOTIFY,\r
1187 VariableAddressChangeEvent,\r
1188 NULL,\r
1189 &gEfiEventVirtualAddressChangeGuid,\r
1190 &mVirtualAddressChangeEvent\r
1191 );\r
fa0737a8 1192\r
8a2d4996 1193 return EFI_SUCCESS;\r
1194}\r
1195\r