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