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