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