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