]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
MdeModulePkg Variable: Add missing warning annotation.
[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
18a7dbbc
SZ
7 Caution: This module requires additional review when modified.\r
8 This driver will have external input - variable data.\r
9 This external input must be validated carefully to avoid security issue like\r
10 buffer overflow, integer overflow.\r
11\r
12 RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API\r
13 to receive data buffer. The size should be checked carefully.\r
14\r
15 InitCommunicateBuffer() is really function to check the variable data size.\r
16\r
4e1005ec 17Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>\r
8a2d4996 18This program and the accompanying materials \r
19are licensed and made available under the terms and conditions of the BSD License \r
20which accompanies this distribution. The full text of the license may be found at \r
21http://opensource.org/licenses/bsd-license.php \r
22\r
23THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
24WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
25\r
26**/\r
d00ed85e 27#include <PiDxe.h>\r
8a2d4996 28#include <Protocol/VariableWrite.h>\r
29#include <Protocol/Variable.h>\r
30#include <Protocol/SmmCommunication.h>\r
d00ed85e 31#include <Protocol/SmmVariable.h>\r
ff843847 32#include <Protocol/VariableLock.h>\r
8a2d4996 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
d00ed85e 46#include <Guid/VariableFormat.h>\r
47#include <Guid/SmmVariableCommon.h>\r
8a2d4996 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
8a2d4996 55UINTN mVariableBufferSize;\r
5e5bb2a9 56UINTN mVariableBufferPayloadSize;\r
6ed1ec59 57EFI_LOCK mVariableServicesLock;\r
ff843847 58EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock;\r
8a2d4996 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
8a2d4996 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
18a7dbbc
SZ
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
8a2d4996 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
32732a33 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
8a2d4996 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
ff843847
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
51547bb8 202 UINTN VariableNameSize;\r
ff843847
RN
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
51547bb8 210 VariableNameSize = StrSize (VariableName);\r
4e1005ec 211 VariableToLock = NULL;\r
51547bb8
RN
212\r
213 //\r
214 // If VariableName exceeds SMM payload limit. Return failure\r
215 //\r
216 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {\r
217 return EFI_INVALID_PARAMETER;\r
218 }\r
219\r
ff843847
RN
220 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
221\r
222 //\r
223 // Init the communicate buffer. The buffer data size is:\r
224 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
225 //\r
51547bb8 226 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;\r
ff843847
RN
227 Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);\r
228 if (EFI_ERROR (Status)) {\r
229 goto Done;\r
230 }\r
231 ASSERT (VariableToLock != NULL);\r
232\r
233 CopyGuid (&VariableToLock->Guid, VendorGuid);\r
51547bb8 234 VariableToLock->NameSize = VariableNameSize;\r
ff843847
RN
235 CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);\r
236\r
237 //\r
238 // Send data to SMM.\r
239 //\r
240 Status = SendCommunicateBuffer (PayloadSize);\r
241\r
242Done:\r
243 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
244 return Status;\r
245}\r
8a2d4996 246\r
247/**\r
248 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
249\r
18a7dbbc
SZ
250 Caution: This function may receive untrusted input.\r
251 The data size is external input, so this function will validate it carefully to avoid buffer overflow.\r
252\r
8a2d4996 253 @param[in] VariableName Name of Variable to be found.\r
254 @param[in] VendorGuid Variable vendor GUID.\r
255 @param[out] Attributes Attribute value of the variable found.\r
256 @param[in, out] DataSize Size of Data found. If size is less than the\r
257 data, this value contains the required size.\r
258 @param[out] Data Data pointer.\r
259 \r
260 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
261 @retval EFI_SUCCESS Find the specified variable.\r
262 @retval EFI_NOT_FOUND Not found.\r
263 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
264\r
265**/\r
266EFI_STATUS\r
267EFIAPI\r
268RuntimeServiceGetVariable (\r
269 IN CHAR16 *VariableName,\r
270 IN EFI_GUID *VendorGuid,\r
271 OUT UINT32 *Attributes OPTIONAL,\r
272 IN OUT UINTN *DataSize,\r
273 OUT VOID *Data\r
274 )\r
275{\r
276 EFI_STATUS Status;\r
277 UINTN PayloadSize;\r
278 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
3a146f2a 279 UINTN TempDataSize;\r
9d00d20e 280 UINTN VariableNameSize;\r
8a2d4996 281\r
282 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
283 return EFI_INVALID_PARAMETER;\r
284 }\r
285\r
286 if ((*DataSize != 0) && (Data == NULL)) {\r
287 return EFI_INVALID_PARAMETER;\r
288 }\r
6ed1ec59 289\r
3a146f2a 290 TempDataSize = *DataSize;\r
9d00d20e 291 VariableNameSize = StrSize (VariableName);\r
4e1005ec 292 SmmVariableHeader = NULL;\r
3a146f2a 293\r
294 //\r
295 // If VariableName exceeds SMM payload limit. Return failure\r
296 //\r
5e5bb2a9 297 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {\r
3588bb35
SZ
298 return EFI_INVALID_PARAMETER;\r
299 }\r
300\r
6ed1ec59
SZ
301 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
302\r
8a2d4996 303 //\r
304 // Init the communicate buffer. The buffer data size is:\r
6ed1ec59 305 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
8a2d4996 306 //\r
5e5bb2a9 307 if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {\r
3a146f2a 308 //\r
309 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
310 //\r
5e5bb2a9 311 TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;\r
3a146f2a 312 }\r
9d00d20e 313 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;\r
3a146f2a 314\r
5c7fa429 315 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);\r
8a2d4996 316 if (EFI_ERROR (Status)) {\r
6ed1ec59 317 goto Done;\r
8a2d4996 318 }\r
319 ASSERT (SmmVariableHeader != NULL);\r
320\r
321 CopyGuid (&SmmVariableHeader->Guid, VendorGuid);\r
3a146f2a 322 SmmVariableHeader->DataSize = TempDataSize;\r
9d00d20e 323 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 324 if (Attributes == NULL) {\r
325 SmmVariableHeader->Attributes = 0;\r
326 } else {\r
327 SmmVariableHeader->Attributes = *Attributes;\r
328 }\r
329 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
330\r
331 //\r
332 // Send data to SMM.\r
333 //\r
334 Status = SendCommunicateBuffer (PayloadSize);\r
335\r
336 //\r
337 // Get data from SMM.\r
338 //\r
3a146f2a 339 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
340 //\r
341 // SMM CommBuffer DataSize can be a trimed value\r
342 // Only update DataSize when needed\r
343 //\r
344 *DataSize = SmmVariableHeader->DataSize;\r
345 }\r
8a2d4996 346 if (Attributes != NULL) {\r
347 *Attributes = SmmVariableHeader->Attributes;\r
348 }\r
349\r
350 if (EFI_ERROR (Status)) {\r
6ed1ec59 351 goto Done;\r
8a2d4996 352 }\r
353\r
354 CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);\r
355\r
6ed1ec59
SZ
356Done:\r
357 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 358 return Status;\r
359}\r
360\r
361\r
362/**\r
363 This code Finds the Next available variable.\r
364\r
365 @param[in, out] VariableNameSize Size of the variable name.\r
366 @param[in, out] VariableName Pointer to variable name.\r
367 @param[in, out] VendorGuid Variable Vendor Guid.\r
368\r
369 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
370 @retval EFI_SUCCESS Find the specified variable.\r
371 @retval EFI_NOT_FOUND Not found.\r
372 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
373\r
374**/\r
375EFI_STATUS\r
376EFIAPI\r
377RuntimeServiceGetNextVariableName (\r
378 IN OUT UINTN *VariableNameSize,\r
379 IN OUT CHAR16 *VariableName,\r
380 IN OUT EFI_GUID *VendorGuid\r
381 )\r
382{\r
383 EFI_STATUS Status;\r
384 UINTN PayloadSize;\r
385 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;\r
9d00d20e
SZ
386 UINTN OutVariableNameSize;\r
387 UINTN InVariableNameSize;\r
8a2d4996 388\r
389 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
390 return EFI_INVALID_PARAMETER;\r
391 }\r
6ed1ec59 392\r
9d00d20e
SZ
393 OutVariableNameSize = *VariableNameSize;\r
394 InVariableNameSize = StrSize (VariableName);\r
4e1005ec 395 SmmGetNextVariableName = NULL;\r
0c55190f 396\r
397 //\r
398 // If input string exceeds SMM payload limit. Return failure\r
399 //\r
5e5bb2a9 400 if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
3588bb35
SZ
401 return EFI_INVALID_PARAMETER;\r
402 }\r
403\r
6ed1ec59
SZ
404 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
405\r
8a2d4996 406 //\r
407 // Init the communicate buffer. The buffer data size is:\r
408 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
409 //\r
5e5bb2a9 410 if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {\r
0c55190f 411 //\r
412 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size\r
413 //\r
5e5bb2a9 414 OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);\r
0c55190f 415 }\r
416 //\r
417 // Payload should be Guid + NameSize + MAX of Input & Output buffer\r
418 //\r
9d00d20e 419 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);\r
0c55190f 420\r
421\r
5c7fa429 422 Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);\r
8a2d4996 423 if (EFI_ERROR (Status)) {\r
6ed1ec59 424 goto Done;\r
8a2d4996 425 }\r
426 ASSERT (SmmGetNextVariableName != NULL);\r
427\r
0c55190f 428 //\r
429 // SMM comm buffer->NameSize is buffer size for return string\r
430 //\r
9d00d20e 431 SmmGetNextVariableName->NameSize = OutVariableNameSize;\r
0c55190f 432\r
8a2d4996 433 CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);\r
0c55190f 434 //\r
435 // Copy whole string\r
436 //\r
9d00d20e
SZ
437 CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);\r
438 if (OutVariableNameSize > InVariableNameSize) {\r
439 ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);\r
440 }\r
8a2d4996 441\r
442 //\r
443 // Send data to SMM\r
444 //\r
445 Status = SendCommunicateBuffer (PayloadSize);\r
446\r
447 //\r
448 // Get data from SMM.\r
449 //\r
9d00d20e
SZ
450 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {\r
451 //\r
452 // SMM CommBuffer NameSize can be a trimed value\r
453 // Only update VariableNameSize when needed\r
454 //\r
455 *VariableNameSize = SmmGetNextVariableName->NameSize;\r
456 }\r
8a2d4996 457 if (EFI_ERROR (Status)) {\r
6ed1ec59 458 goto Done;\r
8a2d4996 459 }\r
460 \r
461 CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);\r
462 CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize); \r
463\r
6ed1ec59
SZ
464Done:\r
465 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 466 return Status;\r
467}\r
468\r
469/**\r
470 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
471\r
18a7dbbc
SZ
472 Caution: This function may receive untrusted input.\r
473 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.\r
474\r
8a2d4996 475 @param[in] VariableName Name of Variable to be found.\r
476 @param[in] VendorGuid Variable vendor GUID.\r
477 @param[in] Attributes Attribute value of the variable found\r
478 @param[in] DataSize Size of Data found. If size is less than the\r
479 data, this value contains the required size.\r
480 @param[in] Data Data pointer.\r
481\r
482 @retval EFI_INVALID_PARAMETER Invalid parameter.\r
483 @retval EFI_SUCCESS Set successfully.\r
484 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
485 @retval EFI_NOT_FOUND Not found.\r
486 @retval EFI_WRITE_PROTECTED Variable is read-only.\r
487\r
488**/\r
489EFI_STATUS\r
490EFIAPI\r
491RuntimeServiceSetVariable (\r
492 IN CHAR16 *VariableName,\r
493 IN EFI_GUID *VendorGuid,\r
494 IN UINT32 Attributes,\r
495 IN UINTN DataSize,\r
496 IN VOID *Data\r
497 )\r
498{\r
499 EFI_STATUS Status;\r
500 UINTN PayloadSize; \r
501 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;\r
9d00d20e 502 UINTN VariableNameSize;\r
8a2d4996 503 \r
504 //\r
505 // Check input parameters.\r
506 //\r
507 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
508 return EFI_INVALID_PARAMETER;\r
509 } \r
510\r
511 if (DataSize != 0 && Data == NULL) {\r
512 return EFI_INVALID_PARAMETER;\r
513 }\r
6ed1ec59 514\r
9d00d20e 515 VariableNameSize = StrSize (VariableName);\r
4e1005ec 516 SmmVariableHeader = NULL;\r
3588bb35 517\r
5e5bb2a9
SZ
518 //\r
519 // If VariableName or DataSize exceeds SMM payload limit. Return failure\r
520 //\r
521 if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||\r
522 (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){\r
56251c66 523 return EFI_INVALID_PARAMETER;\r
524 }\r
525\r
6ed1ec59
SZ
526 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
527 \r
8a2d4996 528 //\r
529 // Init the communicate buffer. The buffer data size is:\r
530 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.\r
531 //\r
9d00d20e 532 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;\r
5c7fa429 533 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);\r
8a2d4996 534 if (EFI_ERROR (Status)) {\r
6ed1ec59 535 goto Done;\r
8a2d4996 536 }\r
537 ASSERT (SmmVariableHeader != NULL);\r
538\r
539 CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);\r
540 SmmVariableHeader->DataSize = DataSize;\r
9d00d20e 541 SmmVariableHeader->NameSize = VariableNameSize;\r
8a2d4996 542 SmmVariableHeader->Attributes = Attributes;\r
543 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);\r
544 CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);\r
545\r
546 //\r
547 // Send data to SMM.\r
548 //\r
549 Status = SendCommunicateBuffer (PayloadSize);\r
6ed1ec59
SZ
550\r
551Done:\r
552 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
8a2d4996 553 return Status;\r
554}\r
555\r
556\r
557/**\r
558 This code returns information about the EFI variables.\r
559\r
560 @param[in] Attributes Attributes bitmask to specify the type of variables\r
561 on which to return information.\r
562 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
563 for the EFI variables associated with the attributes specified.\r
564 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
565 for EFI variables associated with the attributes specified.\r
566 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
567 associated with the attributes specified.\r
568\r
569 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
570 @retval EFI_SUCCESS Query successfully.\r
571 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.\r
572\r
573**/\r
574EFI_STATUS\r
575EFIAPI\r
576RuntimeServiceQueryVariableInfo (\r
577 IN UINT32 Attributes,\r
578 OUT UINT64 *MaximumVariableStorageSize,\r
579 OUT UINT64 *RemainingVariableStorageSize,\r
580 OUT UINT64 *MaximumVariableSize\r
581 )\r
582{\r
583 EFI_STATUS Status;\r
584 UINTN PayloadSize;\r
585 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;\r
586\r
4e1005ec
ED
587 SmmQueryVariableInfo = NULL;\r
588\r
8a2d4996 589 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
590 return EFI_INVALID_PARAMETER;\r
591 }\r
6ed1ec59
SZ
592\r
593 AcquireLockOnlyAtBootTime(&mVariableServicesLock);\r
594\r
8a2d4996 595 //\r
596 // Init the communicate buffer. The buffer data size is:\r
597 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;\r
598 //\r
d00ed85e 599 PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);\r
5c7fa429 600 Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);\r
8a2d4996 601 if (EFI_ERROR (Status)) {\r
6ed1ec59 602 goto Done;\r
8a2d4996 603 }\r
604 ASSERT (SmmQueryVariableInfo != NULL);\r
605\r
606 SmmQueryVariableInfo->Attributes = Attributes;\r
607\r
608 //\r
609 // Send data to SMM.\r
610 //\r
611 Status = SendCommunicateBuffer (PayloadSize);\r
612 if (EFI_ERROR (Status)) {\r
6ed1ec59 613 goto Done;\r
8a2d4996 614 }\r
615\r
616 //\r
617 // Get data from SMM.\r
618 //\r
619 *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;\r
620 *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;\r
621 *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize; \r
6ed1ec59
SZ
622\r
623Done:\r
624 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);\r
aab9212f 625 return Status;\r
8a2d4996 626}\r
627\r
628\r
629/**\r
630 Exit Boot Services Event notification handler.\r
631\r
632 Notify SMM variable driver about the event.\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
640OnExitBootServices (\r
641 IN EFI_EVENT Event,\r
642 IN VOID *Context\r
643 )\r
644{\r
645 //\r
646 // Init the communicate buffer. The buffer data size is:\r
647 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
648 //\r
649 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE); \r
650\r
651 //\r
652 // Send data to SMM.\r
653 //\r
654 SendCommunicateBuffer (0);\r
655}\r
656\r
657\r
658/**\r
659 On Ready To Boot Services Event notification handler.\r
660\r
661 Notify SMM variable driver about the event.\r
662\r
663 @param[in] Event Event whose notification function is being invoked\r
664 @param[in] Context Pointer to the notification function's context\r
665\r
666**/\r
667VOID\r
668EFIAPI\r
669OnReadyToBoot (\r
670 IN EFI_EVENT Event,\r
671 IN VOID *Context\r
672 )\r
673{\r
674 //\r
675 // Init the communicate buffer. The buffer data size is:\r
676 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.\r
677 //\r
678 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);\r
679 \r
680 //\r
681 // Send data to SMM.\r
682 //\r
683 SendCommunicateBuffer (0);\r
684}\r
685\r
686\r
687/**\r
688 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.\r
689\r
690 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
691 It convers pointer to new virtual address.\r
692\r
693 @param[in] Event Event whose notification function is being invoked.\r
694 @param[in] Context Pointer to the notification function's context.\r
695\r
696**/\r
697VOID\r
698EFIAPI\r
699VariableAddressChangeEvent (\r
700 IN EFI_EVENT Event,\r
701 IN VOID *Context\r
702 )\r
703{\r
704 EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);\r
705 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);\r
706}\r
707\r
708\r
709/**\r
710 Initialize variable service and install Variable Architectural protocol.\r
711\r
712 @param[in] Event Event whose notification function is being invoked.\r
713 @param[in] Context Pointer to the notification function's context.\r
714 \r
715**/\r
716VOID\r
717EFIAPI\r
718SmmVariableReady (\r
719 IN EFI_EVENT Event,\r
720 IN VOID *Context\r
721 )\r
722{\r
723 EFI_STATUS Status;\r
724\r
725 Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r
726 if (EFI_ERROR (Status)) {\r
727 return;\r
728 }\r
729 \r
730 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);\r
731 ASSERT_EFI_ERROR (Status);\r
732 \r
733 //\r
5e5bb2a9 734 // Allocate memory for variable communicate buffer.\r
8a2d4996 735 //\r
5e5bb2a9
SZ
736 mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +\r
737 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);\r
738 mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;\r
8a2d4996 739 mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);\r
740 ASSERT (mVariableBuffer != NULL);\r
741\r
742 //\r
743 // Save the buffer physical address used for SMM conmunication.\r
744 //\r
745 mVariableBufferPhysical = mVariableBuffer;\r
746\r
747 gRT->GetVariable = RuntimeServiceGetVariable;\r
748 gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
749 gRT->SetVariable = RuntimeServiceSetVariable;\r
750 gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
751 \r
752 //\r
753 // Install the Variable Architectural Protocol on a new handle.\r
754 //\r
755 Status = gBS->InstallProtocolInterface (\r
756 &mHandle,\r
757 &gEfiVariableArchProtocolGuid, \r
758 EFI_NATIVE_INTERFACE,\r
759 NULL\r
760 );\r
761 ASSERT_EFI_ERROR (Status);\r
762}\r
763\r
764\r
765/**\r
766 SMM Non-Volatile variable write service is ready notify event handler.\r
767\r
768 @param[in] Event Event whose notification function is being invoked.\r
769 @param[in] Context Pointer to the notification function's context.\r
770 \r
771**/\r
772VOID\r
773EFIAPI\r
774SmmVariableWriteReady (\r
775 IN EFI_EVENT Event,\r
776 IN VOID *Context\r
777 )\r
778{\r
779 EFI_STATUS Status;\r
780 VOID *ProtocolOps;\r
781\r
782 //\r
783 // Check whether the protocol is installed or not.\r
784 //\r
d00ed85e 785 Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);\r
8a2d4996 786 if (EFI_ERROR (Status)) {\r
787 return;\r
788 }\r
789 \r
790 Status = gBS->InstallProtocolInterface (\r
791 &mHandle,\r
792 &gEfiVariableWriteArchProtocolGuid, \r
793 EFI_NATIVE_INTERFACE,\r
794 NULL\r
795 );\r
796 ASSERT_EFI_ERROR (Status); \r
797}\r
798\r
799\r
800/**\r
801 Variable Driver main entry point. The Variable driver places the 4 EFI\r
802 runtime services in the EFI System Table and installs arch protocols \r
d00ed85e 803 for variable read and write services being available. It also registers\r
8a2d4996 804 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
805\r
806 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
807 @param[in] SystemTable A pointer to the EFI System Table.\r
808 \r
809 @retval EFI_SUCCESS Variable service successfully initialized.\r
810\r
811**/\r
812EFI_STATUS\r
813EFIAPI\r
814VariableSmmRuntimeInitialize (\r
815 IN EFI_HANDLE ImageHandle,\r
816 IN EFI_SYSTEM_TABLE *SystemTable\r
817 )\r
818{\r
ff843847 819 EFI_STATUS Status;\r
8a2d4996 820 VOID *SmmVariableRegistration;\r
821 VOID *SmmVariableWriteRegistration;\r
822 EFI_EVENT OnReadyToBootEvent;\r
823 EFI_EVENT ExitBootServiceEvent;\r
6ed1ec59
SZ
824\r
825 EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);\r
826\r
ff843847
RN
827 mVariableLock.RequestToLock = VariableLockRequestToLock;\r
828 Status = gBS->InstallMultipleProtocolInterfaces (\r
829 &mHandle,\r
830 &gEdkiiVariableLockProtocolGuid,\r
831 &mVariableLock,\r
832 NULL\r
833 );\r
834 ASSERT_EFI_ERROR (Status);\r
835\r
8a2d4996 836 //\r
837 // Smm variable service is ready\r
838 //\r
839 EfiCreateProtocolNotifyEvent (\r
840 &gEfiSmmVariableProtocolGuid, \r
841 TPL_CALLBACK, \r
842 SmmVariableReady, \r
843 NULL, \r
844 &SmmVariableRegistration\r
845 );\r
846\r
847 //\r
848 // Smm Non-Volatile variable write service is ready\r
849 //\r
850 EfiCreateProtocolNotifyEvent (\r
d00ed85e 851 &gSmmVariableWriteGuid, \r
8a2d4996 852 TPL_CALLBACK, \r
853 SmmVariableWriteReady, \r
854 NULL, \r
855 &SmmVariableWriteRegistration\r
856 );\r
857\r
858 //\r
859 // Register the event to reclaim variable for OS usage.\r
860 //\r
861 EfiCreateEventReadyToBootEx (\r
862 TPL_NOTIFY, \r
863 OnReadyToBoot, \r
864 NULL, \r
865 &OnReadyToBootEvent\r
866 ); \r
867\r
868 //\r
869 // Register the event to inform SMM variable that it is at runtime.\r
870 //\r
871 gBS->CreateEventEx (\r
872 EVT_NOTIFY_SIGNAL,\r
873 TPL_NOTIFY,\r
874 OnExitBootServices,\r
875 NULL,\r
876 &gEfiEventExitBootServicesGuid,\r
877 &ExitBootServiceEvent\r
878 ); \r
879\r
880 //\r
881 // Register the event to convert the pointer for runtime.\r
882 //\r
883 gBS->CreateEventEx (\r
884 EVT_NOTIFY_SIGNAL,\r
885 TPL_NOTIFY,\r
886 VariableAddressChangeEvent,\r
887 NULL,\r
888 &gEfiEventVirtualAddressChangeGuid,\r
889 &mVirtualAddressChangeEvent\r
890 );\r
891 \r
892 return EFI_SUCCESS;\r
893}\r
894\r