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