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