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