]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
1. Fix TOCTOU issue in VariableSmm, FtwSmm, FpdtSmm, SmmCorePerformance SMM handler...
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / VariableSmmRuntimeDxe.c
CommitLineData
8a2d4996 1/** @file\r
2\r
3 Implement all four UEFI Runtime Variable services for the nonvolatile\r
4 and volatile storage space and install variable architecture protocol\r
5 based on SMM variable module.\r
6\r
aab9212f 7Copyright (c) 2010 - 2013, Intel Corporation. All rights reserved.<BR>\r
8a2d4996 8This program and the accompanying materials \r
9are licensed and made available under the terms and conditions of the BSD License \r
10which accompanies this distribution. The full text of the license may be found at \r
11http://opensource.org/licenses/bsd-license.php \r
12\r
13THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
14WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
15\r
16**/\r
d00ed85e 17#include <PiDxe.h>\r
8a2d4996 18#include <Protocol/VariableWrite.h>\r
19#include <Protocol/Variable.h>\r
20#include <Protocol/SmmCommunication.h>\r
d00ed85e 21#include <Protocol/SmmVariable.h>\r
8a2d4996 22\r
23#include <Library/UefiBootServicesTableLib.h>\r
24#include <Library/UefiRuntimeServicesTableLib.h>\r
25#include <Library/MemoryAllocationLib.h>\r
26#include <Library/UefiDriverEntryPoint.h>\r
27#include <Library/UefiRuntimeLib.h>\r
28#include <Library/BaseMemoryLib.h>\r
29#include <Library/DebugLib.h>\r
30#include <Library/PcdLib.h>\r
31#include <Library/UefiLib.h>\r
32#include <Library/BaseLib.h>\r
33\r
34#include <Guid/EventGroup.h>\r
d00ed85e 35#include <Guid/VariableFormat.h>\r
36#include <Guid/SmmVariableCommon.h>\r
8a2d4996 37\r
38EFI_HANDLE mHandle = NULL; \r
39EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;\r
40EFI_EVENT mVirtualAddressChangeEvent = NULL;\r
41EFI_SMM_COMMUNICATION_PROTOCOL *mSmmCommunication = NULL;\r
42UINT8 *mVariableBuffer = NULL;\r
43UINT8 *mVariableBufferPhysical = NULL;\r
8a2d4996 44UINTN mVariableBufferSize;\r
5e5bb2a9 45UINTN mVariableBufferPayloadSize;\r
6ed1ec59 46EFI_LOCK mVariableServicesLock;\r
8a2d4996 47\r
6ed1ec59
SZ
48/**\r
49 Acquires lock only at boot time. Simply returns at runtime.\r
50\r
51 This is a temperary function that will be removed when\r
52 EfiAcquireLock() in UefiLib can handle the call in UEFI\r
53 Runtimer driver in RT phase.\r
54 It calls EfiAcquireLock() at boot time, and simply returns\r
55 at runtime.\r
56\r
57 @param Lock A pointer to the lock to acquire.\r
58\r
59**/\r
60VOID\r
61AcquireLockOnlyAtBootTime (\r
62 IN EFI_LOCK *Lock\r
63 )\r
64{\r
65 if (!EfiAtRuntime ()) {\r
66 EfiAcquireLock (Lock);\r
67 }\r
68}\r
69\r
70/**\r
71 Releases lock only at boot time. Simply returns at runtime.\r
72\r
73 This is a temperary function which will be removed when\r
74 EfiReleaseLock() in UefiLib can handle the call in UEFI\r
75 Runtimer driver in RT phase.\r
76 It calls EfiReleaseLock() at boot time and simply returns\r
77 at runtime.\r
78\r
79 @param Lock A pointer to the lock to release.\r
80\r
81**/\r
82VOID\r
83ReleaseLockOnlyAtBootTime (\r
84 IN EFI_LOCK *Lock\r
85 )\r
86{\r
87 if (!EfiAtRuntime ()) {\r
88 EfiReleaseLock (Lock);\r
89 }\r
90}\r
8a2d4996 91\r
92/**\r
93 Initialize the communicate buffer using DataSize and Function.\r
94\r
95 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +\r
96 DataSize.\r
97\r
98 @param[out] DataPtr Points to the data in the communicate buffer.\r
99 @param[in] DataSize The data size to send to SMM.\r
100 @param[in] Function The function number to initialize the communicate header.\r
101 \r
102 @retval EFI_INVALID_PARAMETER The data size is too big.\r
103 @retval EFI_SUCCESS Find the specified variable.\r
104\r
105**/\r
106EFI_STATUS\r
107InitCommunicateBuffer (\r
108 OUT VOID **DataPtr OPTIONAL,\r
109 IN UINTN DataSize,\r
110 IN UINTN Function\r
111 )\r
112{\r
113 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; \r
114 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader; \r
115\r
116 \r
117 if (DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE > mVariableBufferSize) {\r
118 return EFI_INVALID_PARAMETER;\r
119 }\r
120\r
121 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
122 CopyGuid (&SmmCommunicateHeader->HeaderGuid, &gEfiSmmVariableProtocolGuid);\r
123 SmmCommunicateHeader->MessageLength = DataSize + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
124 \r
125 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *) SmmCommunicateHeader->Data;\r
126 SmmVariableFunctionHeader->Function = Function;\r
127 if (DataPtr != NULL) {\r
128 *DataPtr = SmmVariableFunctionHeader->Data;\r
129 }\r
130\r
131 return EFI_SUCCESS;\r
132}\r
133\r
134\r
135/**\r
136 Send the data in communicate buffer to SMM.\r
137\r
138 @param[in] DataSize This size of the function header and the data.\r
139\r
32732a33 140 @retval EFI_SUCCESS Success is returned from the functin in SMM.\r
141 @retval Others Failure is returned from the function in SMM. \r
8a2d4996 142 \r
143**/\r
144EFI_STATUS\r
145SendCommunicateBuffer (\r
146 IN UINTN DataSize\r
147 )\r
148{\r
149 EFI_STATUS Status;\r
150 UINTN CommSize;\r
151 EFI_SMM_COMMUNICATE_HEADER *SmmCommunicateHeader; \r
152 SMM_VARIABLE_COMMUNICATE_HEADER *SmmVariableFunctionHeader;\r
153 \r
154 CommSize = DataSize + SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE;\r
155 Status = mSmmCommunication->Communicate (mSmmCommunication, mVariableBufferPhysical, &CommSize);\r
156 ASSERT_EFI_ERROR (Status);\r
157\r
158 SmmCommunicateHeader = (EFI_SMM_COMMUNICATE_HEADER *) mVariableBuffer;\r
159 SmmVariableFunctionHeader = (SMM_VARIABLE_COMMUNICATE_HEADER *)SmmCommunicateHeader->Data;\r
160 return SmmVariableFunctionHeader->ReturnStatus;\r
161}\r
162\r
163\r
164/**\r
165 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
166\r
167 @param[in] VariableName Name of Variable to be found.\r
168 @param[in] VendorGuid Variable vendor GUID.\r
169 @param[out] Attributes Attribute value of the variable found.\r
170 @param[in, out] DataSize Size of Data found. If size is less than the\r
171 data, this value contains the required size.\r
172 @param[out] Data Data pointer.\r
173 \r
174 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
175 @retval EFI_SUCCESS Find the specified variable.\r
176 @retval EFI_NOT_FOUND Not found.\r
177 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
178\r
179**/\r
180EFI_STATUS\r
181EFIAPI\r
182RuntimeServiceGetVariable (\r
183 IN CHAR16 *VariableName,\r
184 IN EFI_GUID *VendorGuid,\r
185 OUT UINT32 *Attributes OPTIONAL,\r
186 IN OUT UINTN *DataSize,\r
187 OUT VOID *Data\r
188 )\r
189{\r
190 EFI_STATUS Status;\r
191 UINTN PayloadSize;\r
192 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
3a146f2a 193 UINTN TempDataSize;\r
9d00d20e 194 UINTN VariableNameSize;\r
8a2d4996 195\r
196 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
197 return EFI_INVALID_PARAMETER;\r
198 }\r
199\r
200 if ((*DataSize != 0) && (Data == NULL)) {\r
201 return EFI_INVALID_PARAMETER;\r
202 }\r
6ed1ec59 203\r
3a146f2a 204 TempDataSize = *DataSize;\r
9d00d20e 205 VariableNameSize = StrSize (VariableName);\r
3a146f2a 206\r
207 //\r
208 // If VariableName exceeds SMM payload limit. Return failure\r
209 //\r
5e5bb2a9 210 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
3588bb35
SZ
211 return EFI_INVALID_PARAMETER;\r
212 }\r
213\r
6ed1ec59
SZ
214 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
215\r
8a2d4996 216 //\r
217 // Init the communicate buffer. The buffer data size is:\r
6ed1ec59 218 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
8a2d4996 219 //\r
5e5bb2a9 220 if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {\r
3a146f2a 221 //\r
222 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
223 //\r
5e5bb2a9 224 TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;\r
3a146f2a 225 }\r
9d00d20e 226 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
3a146f2a 227\r
5c7fa429 228 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
8a2d4996 229 if (EFI_ERROR (Status)) {\r
6ed1ec59 230 goto Done;\r
8a2d4996 231 }\r
232 ASSERT (SmmVariableHeader != NULL);\r
233\r
234 CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
3a146f2a 235 SmmVariableHeader->DataSize = TempDataSize;\r
9d00d20e 236 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 237 if (Attributes == NULL) {\r
238 SmmVariableHeader->Attributes = 0;\r
239 } else {\r
240 SmmVariableHeader->Attributes = *Attributes;\r
241 }\r
242 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
243\r
244 //\r
245 // Send data to SMM.\r
246 //\r
247 Status = SendCommunicateBuffer (PayloadSize);\r
248\r
249 //\r
250 // Get data from SMM.\r
251 //\r
3a146f2a 252 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
253 //\r
254 // SMM CommBuffer DataSize can be a trimed value\r
255 // Only update DataSize when needed\r
256 //\r
257 *DataSize = SmmVariableHeader->DataSize;\r
258 }\r
8a2d4996 259 if (Attributes != NULL) {\r
260 *Attributes = SmmVariableHeader->Attributes;\r
261 }\r
262\r
263 if (EFI_ERROR (Status)) {\r
6ed1ec59 264 goto Done;\r
8a2d4996 265 }\r
266\r
267 CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
268\r
6ed1ec59
SZ
269Done:\r
270 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 271 return Status;\r
272}\r
273\r
274\r
275/**\r
276 This code Finds the Next available variable.\r
277\r
278 @param[in, out] VariableNameSize Size of the variable name.\r
279 @param[in, out] VariableName Pointer to variable name.\r
280 @param[in, out] VendorGuid Variable Vendor Guid.\r
281\r
282 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
283 @retval EFI_SUCCESS Find the specified variable.\r
284 @retval EFI_NOT_FOUND Not found.\r
285 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
286\r
287**/\r
288EFI_STATUS\r
289EFIAPI\r
290RuntimeServiceGetNextVariableName (\r
291 IN OUT UINTN *VariableNameSize,\r
292 IN OUT CHAR16 *VariableName,\r
293 IN OUT EFI_GUID *VendorGuid\r
294 )\r
295{\r
296 EFI_STATUS Status;\r
297 UINTN PayloadSize;\r
298 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
9d00d20e
SZ
299 UINTN OutVariableNameSize;\r
300 UINTN InVariableNameSize;\r
8a2d4996 301\r
302 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
303 return EFI_INVALID_PARAMETER;\r
304 }\r
6ed1ec59 305\r
9d00d20e
SZ
306 OutVariableNameSize = *VariableNameSize;\r
307 InVariableNameSize = StrSize (VariableName);\r
0c55190f 308\r
309 //\r
310 // If input string exceeds SMM payload limit. Return failure\r
311 //\r
5e5bb2a9 312 if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
3588bb35
SZ
313 return EFI_INVALID_PARAMETER;\r
314 }\r
315\r
6ed1ec59
SZ
316 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
317\r
8a2d4996 318 //\r
319 // Init the communicate buffer. The buffer data size is:\r
320 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
321 //\r
5e5bb2a9 322 if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
0c55190f 323 //\r
324 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
325 //\r
5e5bb2a9 326 OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
0c55190f 327 }\r
328 //\r
329 // Payload should be Guid + NameSize + MAX of Input & Output buffer\r
330 //\r
9d00d20e 331 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);\r
0c55190f 332\r
333\r
5c7fa429 334 Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
8a2d4996 335 if (EFI_ERROR (Status)) {\r
6ed1ec59 336 goto Done;\r
8a2d4996 337 }\r
338 ASSERT (SmmGetNextVariableName != NULL);\r
339\r
0c55190f 340 //\r
341 // SMM comm buffer->NameSize is buffer size for return string\r
342 //\r
9d00d20e 343 SmmGetNextVariableName->NameSize = OutVariableNameSize;\r
0c55190f 344\r
8a2d4996 345 CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
0c55190f 346 //\r
347 // Copy whole string\r
348 //\r
9d00d20e
SZ
349 CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);\r
350 if (OutVariableNameSize > InVariableNameSize) {\r
351 ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
352 }\r
8a2d4996 353\r
354 //\r
355 // Send data to SMM\r
356 //\r
357 Status = SendCommunicateBuffer (PayloadSize);\r
358\r
359 //\r
360 // Get data from SMM.\r
361 //\r
9d00d20e
SZ
362 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
363 //\r
364 // SMM CommBuffer NameSize can be a trimed value\r
365 // Only update VariableNameSize when needed\r
366 //\r
367 *VariableNameSize = SmmGetNextVariableName->NameSize;\r
368 }\r
8a2d4996 369 if (EFI_ERROR (Status)) {\r
6ed1ec59 370 goto Done;\r
8a2d4996 371 }\r
372 \r
373 CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
374 CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize); \r
375\r
6ed1ec59
SZ
376Done:\r
377 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 378 return Status;\r
379}\r
380\r
381/**\r
382 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
383\r
384 @param[in] VariableName Name of Variable to be found.\r
385 @param[in] VendorGuid Variable vendor GUID.\r
386 @param[in] Attributes Attribute value of the variable found\r
387 @param[in] DataSize Size of Data found. If size is less than the\r
388 data, this value contains the required size.\r
389 @param[in] Data Data pointer.\r
390\r
391 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
392 @retval EFI_SUCCESS Set successfully.\r
393 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
394 @retval EFI_NOT_FOUND Not found.\r
395 @retval EFI_WRITE_PROTECTED Variable is read-only.\r
396\r
397**/\r
398EFI_STATUS\r
399EFIAPI\r
400RuntimeServiceSetVariable (\r
401 IN CHAR16 *VariableName,\r
402 IN EFI_GUID *VendorGuid,\r
403 IN UINT32 Attributes,\r
404 IN UINTN DataSize,\r
405 IN VOID *Data\r
406 )\r
407{\r
408 EFI_STATUS Status;\r
409 UINTN PayloadSize; \r
410 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
9d00d20e 411 UINTN VariableNameSize;\r
8a2d4996 412 \r
413 //\r
414 // Check input parameters.\r
415 //\r
416 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
417 return EFI_INVALID_PARAMETER;\r
418 } \r
419\r
420 if (DataSize != 0 && Data == NULL) {\r
421 return EFI_INVALID_PARAMETER;\r
422 }\r
6ed1ec59 423\r
9d00d20e 424 VariableNameSize = StrSize (VariableName);\r
3588bb35 425\r
5e5bb2a9
SZ
426 //\r
427 // If VariableName or DataSize exceeds SMM payload limit. Return failure\r
428 //\r
429 if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
430 (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){\r
56251c66 431 return EFI_INVALID_PARAMETER;\r
432 }\r
433\r
6ed1ec59
SZ
434 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
435 \r
8a2d4996 436 //\r
437 // Init the communicate buffer. The buffer data size is:\r
438 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
439 //\r
9d00d20e 440 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;\r
5c7fa429 441 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
8a2d4996 442 if (EFI_ERROR (Status)) {\r
6ed1ec59 443 goto Done;\r
8a2d4996 444 }\r
445 ASSERT (SmmVariableHeader != NULL);\r
446\r
447 CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
448 SmmVariableHeader->DataSize = DataSize;\r
9d00d20e 449 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 450 SmmVariableHeader->Attributes = Attributes;\r
451 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
452 CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
453\r
454 //\r
455 // Send data to SMM.\r
456 //\r
457 Status = SendCommunicateBuffer (PayloadSize);\r
6ed1ec59
SZ
458\r
459Done:\r
460 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 461 return Status;\r
462}\r
463\r
464\r
465/**\r
466 This code returns information about the EFI variables.\r
467\r
468 @param[in] Attributes Attributes bitmask to specify the type of variables\r
469 on which to return information.\r
470 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
471 for the EFI variables associated with the attributes specified.\r
472 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
473 for EFI variables associated with the attributes specified.\r
474 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
475 associated with the attributes specified.\r
476\r
477 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
478 @retval EFI_SUCCESS Query successfully.\r
479 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.\r
480\r
481**/\r
482EFI_STATUS\r
483EFIAPI\r
484RuntimeServiceQueryVariableInfo (\r
485 IN UINT32 Attributes,\r
486 OUT UINT64 *MaximumVariableStorageSize,\r
487 OUT UINT64 *RemainingVariableStorageSize,\r
488 OUT UINT64 *MaximumVariableSize\r
489 )\r
490{\r
491 EFI_STATUS Status;\r
492 UINTN PayloadSize;\r
493 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
494\r
495 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
496 return EFI_INVALID_PARAMETER;\r
497 }\r
6ed1ec59
SZ
498\r
499 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
500\r
8a2d4996 501 //\r
502 // Init the communicate buffer. The buffer data size is:\r
503 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
504 //\r
d00ed85e 505 PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
5c7fa429 506 Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
8a2d4996 507 if (EFI_ERROR (Status)) {\r
6ed1ec59 508 goto Done;\r
8a2d4996 509 }\r
510 ASSERT (SmmQueryVariableInfo != NULL);\r
511\r
512 SmmQueryVariableInfo->Attributes = Attributes;\r
513\r
514 //\r
515 // Send data to SMM.\r
516 //\r
517 Status = SendCommunicateBuffer (PayloadSize);\r
518 if (EFI_ERROR (Status)) {\r
6ed1ec59 519 goto Done;\r
8a2d4996 520 }\r
521\r
522 //\r
523 // Get data from SMM.\r
524 //\r
525 *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;\r
526 *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
527 *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; \r
6ed1ec59
SZ
528\r
529Done:\r
530 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
aab9212f 531 return Status;\r
8a2d4996 532}\r
533\r
534\r
535/**\r
536 Exit Boot Services Event notification handler.\r
537\r
538 Notify SMM variable driver about the event.\r
539\r
540 @param[in] Event Event whose notification function is being invoked.\r
541 @param[in] Context Pointer to the notification function's context.\r
542\r
543**/\r
544VOID\r
545EFIAPI\r
546OnExitBootServices (\r
547 IN EFI_EVENT Event,\r
548 IN VOID *Context\r
549 )\r
550{\r
551 //\r
552 // Init the communicate buffer. The buffer data size is:\r
553 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
554 //\r
555 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); \r
556\r
557 //\r
558 // Send data to SMM.\r
559 //\r
560 SendCommunicateBuffer (0);\r
561}\r
562\r
563\r
564/**\r
565 On Ready To Boot Services Event notification handler.\r
566\r
567 Notify SMM variable driver about the event.\r
568\r
569 @param[in] Event Event whose notification function is being invoked\r
570 @param[in] Context Pointer to the notification function's context\r
571\r
572**/\r
573VOID\r
574EFIAPI\r
575OnReadyToBoot (\r
576 IN EFI_EVENT Event,\r
577 IN VOID *Context\r
578 )\r
579{\r
580 //\r
581 // Init the communicate buffer. The buffer data size is:\r
582 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
583 //\r
584 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
585 \r
586 //\r
587 // Send data to SMM.\r
588 //\r
589 SendCommunicateBuffer (0);\r
590}\r
591\r
592\r
593/**\r
594 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
595\r
596 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
597 It convers pointer to new virtual address.\r
598\r
599 @param[in] Event Event whose notification function is being invoked.\r
600 @param[in] Context Pointer to the notification function's context.\r
601\r
602**/\r
603VOID\r
604EFIAPI\r
605VariableAddressChangeEvent (\r
606 IN EFI_EVENT Event,\r
607 IN VOID *Context\r
608 )\r
609{\r
610 EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
611 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
612}\r
613\r
614\r
615/**\r
616 Initialize variable service and install Variable Architectural protocol.\r
617\r
618 @param[in] Event Event whose notification function is being invoked.\r
619 @param[in] Context Pointer to the notification function's context.\r
620 \r
621**/\r
622VOID\r
623EFIAPI\r
624SmmVariableReady (\r
625 IN EFI_EVENT Event,\r
626 IN VOID *Context\r
627 )\r
628{\r
629 EFI_STATUS Status;\r
630\r
631 Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r
632 if (EFI_ERROR (Status)) {\r
633 return;\r
634 }\r
635 \r
636 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
637 ASSERT_EFI_ERROR (Status);\r
638 \r
639 //\r
5e5bb2a9 640 // Allocate memory for variable communicate buffer.\r
8a2d4996 641 //\r
5e5bb2a9
SZ
642 mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +\r
643 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);\r
644 mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
8a2d4996 645 mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);\r
646 ASSERT (mVariableBuffer != NULL);\r
647\r
648 //\r
649 // Save the buffer physical address used for SMM conmunication.\r
650 //\r
651 mVariableBufferPhysical = mVariableBuffer;\r
652\r
653 gRT->GetVariable = RuntimeServiceGetVariable;\r
654 gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
655 gRT->SetVariable = RuntimeServiceSetVariable;\r
656 gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
657 \r
658 //\r
659 // Install the Variable Architectural Protocol on a new handle.\r
660 //\r
661 Status = gBS->InstallProtocolInterface (\r
662 &mHandle,\r
663 &gEfiVariableArchProtocolGuid, \r
664 EFI_NATIVE_INTERFACE,\r
665 NULL\r
666 );\r
667 ASSERT_EFI_ERROR (Status);\r
668}\r
669\r
670\r
671/**\r
672 SMM Non-Volatile variable write service is ready notify event handler.\r
673\r
674 @param[in] Event Event whose notification function is being invoked.\r
675 @param[in] Context Pointer to the notification function's context.\r
676 \r
677**/\r
678VOID\r
679EFIAPI\r
680SmmVariableWriteReady (\r
681 IN EFI_EVENT Event,\r
682 IN VOID *Context\r
683 )\r
684{\r
685 EFI_STATUS Status;\r
686 VOID *ProtocolOps;\r
687\r
688 //\r
689 // Check whether the protocol is installed or not.\r
690 //\r
d00ed85e 691 Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
8a2d4996 692 if (EFI_ERROR (Status)) {\r
693 return;\r
694 }\r
695 \r
696 Status = gBS->InstallProtocolInterface (\r
697 &mHandle,\r
698 &gEfiVariableWriteArchProtocolGuid, \r
699 EFI_NATIVE_INTERFACE,\r
700 NULL\r
701 );\r
702 ASSERT_EFI_ERROR (Status); \r
703}\r
704\r
705\r
706/**\r
707 Variable Driver main entry point. The Variable driver places the 4 EFI\r
708 runtime services in the EFI System Table and installs arch protocols \r
d00ed85e 709 for variable read and write services being available. It also registers\r
8a2d4996 710 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
711\r
712 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
713 @param[in] SystemTable A pointer to the EFI System Table.\r
714 \r
715 @retval EFI_SUCCESS Variable service successfully initialized.\r
716\r
717**/\r
718EFI_STATUS\r
719EFIAPI\r
720VariableSmmRuntimeInitialize (\r
721 IN EFI_HANDLE ImageHandle,\r
722 IN EFI_SYSTEM_TABLE *SystemTable\r
723 )\r
724{\r
725 VOID *SmmVariableRegistration;\r
726 VOID *SmmVariableWriteRegistration;\r
727 EFI_EVENT OnReadyToBootEvent;\r
728 EFI_EVENT ExitBootServiceEvent;\r
6ed1ec59
SZ
729\r
730 EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\r
731\r
8a2d4996 732 //\r
733 // Smm variable service is ready\r
734 //\r
735 EfiCreateProtocolNotifyEvent (\r
736 &gEfiSmmVariableProtocolGuid, \r
737 TPL_CALLBACK, \r
738 SmmVariableReady, \r
739 NULL, \r
740 &SmmVariableRegistration\r
741 );\r
742\r
743 //\r
744 // Smm Non-Volatile variable write service is ready\r
745 //\r
746 EfiCreateProtocolNotifyEvent (\r
d00ed85e 747 &gSmmVariableWriteGuid, \r
8a2d4996 748 TPL_CALLBACK, \r
749 SmmVariableWriteReady, \r
750 NULL, \r
751 &SmmVariableWriteRegistration\r
752 );\r
753\r
754 //\r
755 // Register the event to reclaim variable for OS usage.\r
756 //\r
757 EfiCreateEventReadyToBootEx (\r
758 TPL_NOTIFY, \r
759 OnReadyToBoot, \r
760 NULL, \r
761 &OnReadyToBootEvent\r
762 ); \r
763\r
764 //\r
765 // Register the event to inform SMM variable that it is at runtime.\r
766 //\r
767 gBS->CreateEventEx (\r
768 EVT_NOTIFY_SIGNAL,\r
769 TPL_NOTIFY,\r
770 OnExitBootServices,\r
771 NULL,\r
772 &gEfiEventExitBootServicesGuid,\r
773 &ExitBootServiceEvent\r
774 ); \r
775\r
776 //\r
777 // Register the event to convert the pointer for runtime.\r
778 //\r
779 gBS->CreateEventEx (\r
780 EVT_NOTIFY_SIGNAL,\r
781 TPL_NOTIFY,\r
782 VariableAddressChangeEvent,\r
783 NULL,\r
784 &gEfiEventVirtualAddressChangeGuid,\r
785 &mVirtualAddressChangeEvent\r
786 );\r
787 \r
788 return EFI_SUCCESS;\r
789}\r
790\r