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