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