]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.c
MdeModulePkg: INF/DEC file updates to EDK II packages
[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 - 2014, 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 VariableToLock = NULL;
199
200 //
201 // If VariableName exceeds SMM payload limit. Return failure
202 //
203 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name)) {
204 return EFI_INVALID_PARAMETER;
205 }
206
207 AcquireLockOnlyAtBootTime(&mVariableServicesLock);
208
209 //
210 // Init the communicate buffer. The buffer data size is:
211 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
212 //
213 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE, Name) + VariableNameSize;
214 Status = InitCommunicateBuffer ((VOID **) &VariableToLock, PayloadSize, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE);
215 if (EFI_ERROR (Status)) {
216 goto Done;
217 }
218 ASSERT (VariableToLock != NULL);
219
220 CopyGuid (&VariableToLock->Guid, VendorGuid);
221 VariableToLock->NameSize = VariableNameSize;
222 CopyMem (VariableToLock->Name, VariableName, VariableToLock->NameSize);
223
224 //
225 // Send data to SMM.
226 //
227 Status = SendCommunicateBuffer (PayloadSize);
228
229 Done:
230 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
231 return Status;
232 }
233
234 /**
235 This code finds variable in storage blocks (Volatile or Non-Volatile).
236
237 @param[in] VariableName Name of Variable to be found.
238 @param[in] VendorGuid Variable vendor GUID.
239 @param[out] Attributes Attribute value of the variable found.
240 @param[in, out] DataSize Size of Data found. If size is less than the
241 data, this value contains the required size.
242 @param[out] Data Data pointer.
243
244 @retval EFI_INVALID_PARAMETER Invalid parameter.
245 @retval EFI_SUCCESS Find the specified variable.
246 @retval EFI_NOT_FOUND Not found.
247 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
248
249 **/
250 EFI_STATUS
251 EFIAPI
252 RuntimeServiceGetVariable (
253 IN CHAR16 *VariableName,
254 IN EFI_GUID *VendorGuid,
255 OUT UINT32 *Attributes OPTIONAL,
256 IN OUT UINTN *DataSize,
257 OUT VOID *Data
258 )
259 {
260 EFI_STATUS Status;
261 UINTN PayloadSize;
262 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
263 UINTN TempDataSize;
264 UINTN VariableNameSize;
265
266 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
267 return EFI_INVALID_PARAMETER;
268 }
269
270 if ((*DataSize != 0) && (Data == NULL)) {
271 return EFI_INVALID_PARAMETER;
272 }
273
274 TempDataSize = *DataSize;
275 VariableNameSize = StrSize (VariableName);
276 SmmVariableHeader = NULL;
277
278 //
279 // If VariableName exceeds SMM payload limit. Return failure
280 //
281 if (VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) {
282 return EFI_INVALID_PARAMETER;
283 }
284
285 AcquireLockOnlyAtBootTime(&mVariableServicesLock);
286
287 //
288 // Init the communicate buffer. The buffer data size is:
289 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
290 //
291 if (TempDataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize) {
292 //
293 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
294 //
295 TempDataSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize;
296 }
297 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + TempDataSize;
298
299 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_GET_VARIABLE);
300 if (EFI_ERROR (Status)) {
301 goto Done;
302 }
303 ASSERT (SmmVariableHeader != NULL);
304
305 CopyGuid (&SmmVariableHeader->Guid, VendorGuid);
306 SmmVariableHeader->DataSize = TempDataSize;
307 SmmVariableHeader->NameSize = VariableNameSize;
308 if (Attributes == NULL) {
309 SmmVariableHeader->Attributes = 0;
310 } else {
311 SmmVariableHeader->Attributes = *Attributes;
312 }
313 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
314
315 //
316 // Send data to SMM.
317 //
318 Status = SendCommunicateBuffer (PayloadSize);
319
320 //
321 // Get data from SMM.
322 //
323 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
324 //
325 // SMM CommBuffer DataSize can be a trimed value
326 // Only update DataSize when needed
327 //
328 *DataSize = SmmVariableHeader->DataSize;
329 }
330 if (Attributes != NULL) {
331 *Attributes = SmmVariableHeader->Attributes;
332 }
333
334 if (EFI_ERROR (Status)) {
335 goto Done;
336 }
337
338 CopyMem (Data, (UINT8 *)SmmVariableHeader->Name + SmmVariableHeader->NameSize, SmmVariableHeader->DataSize);
339
340 Done:
341 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
342 return Status;
343 }
344
345
346 /**
347 This code Finds the Next available variable.
348
349 @param[in, out] VariableNameSize Size of the variable name.
350 @param[in, out] VariableName Pointer to variable name.
351 @param[in, out] VendorGuid Variable Vendor Guid.
352
353 @retval EFI_INVALID_PARAMETER Invalid parameter.
354 @retval EFI_SUCCESS Find the specified variable.
355 @retval EFI_NOT_FOUND Not found.
356 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
357
358 **/
359 EFI_STATUS
360 EFIAPI
361 RuntimeServiceGetNextVariableName (
362 IN OUT UINTN *VariableNameSize,
363 IN OUT CHAR16 *VariableName,
364 IN OUT EFI_GUID *VendorGuid
365 )
366 {
367 EFI_STATUS Status;
368 UINTN PayloadSize;
369 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME *SmmGetNextVariableName;
370 UINTN OutVariableNameSize;
371 UINTN InVariableNameSize;
372
373 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
374 return EFI_INVALID_PARAMETER;
375 }
376
377 OutVariableNameSize = *VariableNameSize;
378 InVariableNameSize = StrSize (VariableName);
379 SmmGetNextVariableName = NULL;
380
381 //
382 // If input string exceeds SMM payload limit. Return failure
383 //
384 if (InVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
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 if (OutVariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name)) {
395 //
396 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
397 //
398 OutVariableNameSize = mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name);
399 }
400 //
401 // Payload should be Guid + NameSize + MAX of Input & Output buffer
402 //
403 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME, Name) + MAX (OutVariableNameSize, InVariableNameSize);
404
405
406 Status = InitCommunicateBuffer ((VOID **)&SmmGetNextVariableName, PayloadSize, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME);
407 if (EFI_ERROR (Status)) {
408 goto Done;
409 }
410 ASSERT (SmmGetNextVariableName != NULL);
411
412 //
413 // SMM comm buffer->NameSize is buffer size for return string
414 //
415 SmmGetNextVariableName->NameSize = OutVariableNameSize;
416
417 CopyGuid (&SmmGetNextVariableName->Guid, VendorGuid);
418 //
419 // Copy whole string
420 //
421 CopyMem (SmmGetNextVariableName->Name, VariableName, InVariableNameSize);
422 if (OutVariableNameSize > InVariableNameSize) {
423 ZeroMem ((UINT8 *) SmmGetNextVariableName->Name + InVariableNameSize, OutVariableNameSize - InVariableNameSize);
424 }
425
426 //
427 // Send data to SMM
428 //
429 Status = SendCommunicateBuffer (PayloadSize);
430
431 //
432 // Get data from SMM.
433 //
434 if (Status == EFI_SUCCESS || Status == EFI_BUFFER_TOO_SMALL) {
435 //
436 // SMM CommBuffer NameSize can be a trimed value
437 // Only update VariableNameSize when needed
438 //
439 *VariableNameSize = SmmGetNextVariableName->NameSize;
440 }
441 if (EFI_ERROR (Status)) {
442 goto Done;
443 }
444
445 CopyGuid (VendorGuid, &SmmGetNextVariableName->Guid);
446 CopyMem (VariableName, SmmGetNextVariableName->Name, SmmGetNextVariableName->NameSize);
447
448 Done:
449 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
450 return Status;
451 }
452
453 /**
454 This code sets variable in storage blocks (Volatile or Non-Volatile).
455
456 @param[in] VariableName Name of Variable to be found.
457 @param[in] VendorGuid Variable vendor GUID.
458 @param[in] Attributes Attribute value of the variable found
459 @param[in] DataSize Size of Data found. If size is less than the
460 data, this value contains the required size.
461 @param[in] Data Data pointer.
462
463 @retval EFI_INVALID_PARAMETER Invalid parameter.
464 @retval EFI_SUCCESS Set successfully.
465 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
466 @retval EFI_NOT_FOUND Not found.
467 @retval EFI_WRITE_PROTECTED Variable is read-only.
468
469 **/
470 EFI_STATUS
471 EFIAPI
472 RuntimeServiceSetVariable (
473 IN CHAR16 *VariableName,
474 IN EFI_GUID *VendorGuid,
475 IN UINT32 Attributes,
476 IN UINTN DataSize,
477 IN VOID *Data
478 )
479 {
480 EFI_STATUS Status;
481 UINTN PayloadSize;
482 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE *SmmVariableHeader;
483 UINTN VariableNameSize;
484
485 //
486 // Check input parameters.
487 //
488 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
489 return EFI_INVALID_PARAMETER;
490 }
491
492 if (DataSize != 0 && Data == NULL) {
493 return EFI_INVALID_PARAMETER;
494 }
495
496 VariableNameSize = StrSize (VariableName);
497 SmmVariableHeader = NULL;
498
499 //
500 // If VariableName or DataSize exceeds SMM payload limit. Return failure
501 //
502 if ((VariableNameSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name)) ||
503 (DataSize > mVariableBufferPayloadSize - OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - VariableNameSize)){
504 return EFI_INVALID_PARAMETER;
505 }
506
507 AcquireLockOnlyAtBootTime(&mVariableServicesLock);
508
509 //
510 // Init the communicate buffer. The buffer data size is:
511 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
512 //
513 PayloadSize = OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) + VariableNameSize + DataSize;
514 Status = InitCommunicateBuffer ((VOID **)&SmmVariableHeader, PayloadSize, SMM_VARIABLE_FUNCTION_SET_VARIABLE);
515 if (EFI_ERROR (Status)) {
516 goto Done;
517 }
518 ASSERT (SmmVariableHeader != NULL);
519
520 CopyGuid ((EFI_GUID *) &SmmVariableHeader->Guid, VendorGuid);
521 SmmVariableHeader->DataSize = DataSize;
522 SmmVariableHeader->NameSize = VariableNameSize;
523 SmmVariableHeader->Attributes = Attributes;
524 CopyMem (SmmVariableHeader->Name, VariableName, SmmVariableHeader->NameSize);
525 CopyMem ((UINT8 *) SmmVariableHeader->Name + SmmVariableHeader->NameSize, Data, DataSize);
526
527 //
528 // Send data to SMM.
529 //
530 Status = SendCommunicateBuffer (PayloadSize);
531
532 Done:
533 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
534 return Status;
535 }
536
537
538 /**
539 This code returns information about the EFI variables.
540
541 @param[in] Attributes Attributes bitmask to specify the type of variables
542 on which to return information.
543 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
544 for the EFI variables associated with the attributes specified.
545 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
546 for EFI variables associated with the attributes specified.
547 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
548 associated with the attributes specified.
549
550 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
551 @retval EFI_SUCCESS Query successfully.
552 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
553
554 **/
555 EFI_STATUS
556 EFIAPI
557 RuntimeServiceQueryVariableInfo (
558 IN UINT32 Attributes,
559 OUT UINT64 *MaximumVariableStorageSize,
560 OUT UINT64 *RemainingVariableStorageSize,
561 OUT UINT64 *MaximumVariableSize
562 )
563 {
564 EFI_STATUS Status;
565 UINTN PayloadSize;
566 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO *SmmQueryVariableInfo;
567
568 SmmQueryVariableInfo = NULL;
569
570 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
571 return EFI_INVALID_PARAMETER;
572 }
573
574 AcquireLockOnlyAtBootTime(&mVariableServicesLock);
575
576 //
577 // Init the communicate buffer. The buffer data size is:
578 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
579 //
580 PayloadSize = sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO);
581 Status = InitCommunicateBuffer ((VOID **)&SmmQueryVariableInfo, PayloadSize, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO);
582 if (EFI_ERROR (Status)) {
583 goto Done;
584 }
585 ASSERT (SmmQueryVariableInfo != NULL);
586
587 SmmQueryVariableInfo->Attributes = Attributes;
588
589 //
590 // Send data to SMM.
591 //
592 Status = SendCommunicateBuffer (PayloadSize);
593 if (EFI_ERROR (Status)) {
594 goto Done;
595 }
596
597 //
598 // Get data from SMM.
599 //
600 *MaximumVariableSize = SmmQueryVariableInfo->MaximumVariableSize;
601 *MaximumVariableStorageSize = SmmQueryVariableInfo->MaximumVariableStorageSize;
602 *RemainingVariableStorageSize = SmmQueryVariableInfo->RemainingVariableStorageSize;
603
604 Done:
605 ReleaseLockOnlyAtBootTime (&mVariableServicesLock);
606 return Status;
607 }
608
609
610 /**
611 Exit Boot Services Event notification handler.
612
613 Notify SMM variable driver about the event.
614
615 @param[in] Event Event whose notification function is being invoked.
616 @param[in] Context Pointer to the notification function's context.
617
618 **/
619 VOID
620 EFIAPI
621 OnExitBootServices (
622 IN EFI_EVENT Event,
623 IN VOID *Context
624 )
625 {
626 //
627 // Init the communicate buffer. The buffer data size is:
628 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
629 //
630 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE);
631
632 //
633 // Send data to SMM.
634 //
635 SendCommunicateBuffer (0);
636 }
637
638
639 /**
640 On Ready To Boot Services Event notification handler.
641
642 Notify SMM variable driver about the event.
643
644 @param[in] Event Event whose notification function is being invoked
645 @param[in] Context Pointer to the notification function's context
646
647 **/
648 VOID
649 EFIAPI
650 OnReadyToBoot (
651 IN EFI_EVENT Event,
652 IN VOID *Context
653 )
654 {
655 //
656 // Init the communicate buffer. The buffer data size is:
657 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
658 //
659 InitCommunicateBuffer (NULL, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT);
660
661 //
662 // Send data to SMM.
663 //
664 SendCommunicateBuffer (0);
665 }
666
667
668 /**
669 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
670
671 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
672 It convers pointer to new virtual address.
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 VariableAddressChangeEvent (
681 IN EFI_EVENT Event,
682 IN VOID *Context
683 )
684 {
685 EfiConvertPointer (0x0, (VOID **) &mVariableBuffer);
686 EfiConvertPointer (0x0, (VOID **) &mSmmCommunication);
687 }
688
689
690 /**
691 Initialize variable service and install Variable Architectural protocol.
692
693 @param[in] Event Event whose notification function is being invoked.
694 @param[in] Context Pointer to the notification function's context.
695
696 **/
697 VOID
698 EFIAPI
699 SmmVariableReady (
700 IN EFI_EVENT Event,
701 IN VOID *Context
702 )
703 {
704 EFI_STATUS Status;
705
706 Status = gBS->LocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);
707 if (EFI_ERROR (Status)) {
708 return;
709 }
710
711 Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &mSmmCommunication);
712 ASSERT_EFI_ERROR (Status);
713
714 //
715 // Allocate memory for variable communicate buffer.
716 //
717 mVariableBufferPayloadSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) +
718 OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE, Name) - sizeof (VARIABLE_HEADER);
719 mVariableBufferSize = SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + mVariableBufferPayloadSize;
720 mVariableBuffer = AllocateRuntimePool (mVariableBufferSize);
721 ASSERT (mVariableBuffer != NULL);
722
723 //
724 // Save the buffer physical address used for SMM conmunication.
725 //
726 mVariableBufferPhysical = mVariableBuffer;
727
728 gRT->GetVariable = RuntimeServiceGetVariable;
729 gRT->GetNextVariableName = RuntimeServiceGetNextVariableName;
730 gRT->SetVariable = RuntimeServiceSetVariable;
731 gRT->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
732
733 //
734 // Install the Variable Architectural Protocol on a new handle.
735 //
736 Status = gBS->InstallProtocolInterface (
737 &mHandle,
738 &gEfiVariableArchProtocolGuid,
739 EFI_NATIVE_INTERFACE,
740 NULL
741 );
742 ASSERT_EFI_ERROR (Status);
743 }
744
745
746 /**
747 SMM Non-Volatile variable write service is ready notify event handler.
748
749 @param[in] Event Event whose notification function is being invoked.
750 @param[in] Context Pointer to the notification function's context.
751
752 **/
753 VOID
754 EFIAPI
755 SmmVariableWriteReady (
756 IN EFI_EVENT Event,
757 IN VOID *Context
758 )
759 {
760 EFI_STATUS Status;
761 VOID *ProtocolOps;
762
763 //
764 // Check whether the protocol is installed or not.
765 //
766 Status = gBS->LocateProtocol (&gSmmVariableWriteGuid, NULL, (VOID **) &ProtocolOps);
767 if (EFI_ERROR (Status)) {
768 return;
769 }
770
771 Status = gBS->InstallProtocolInterface (
772 &mHandle,
773 &gEfiVariableWriteArchProtocolGuid,
774 EFI_NATIVE_INTERFACE,
775 NULL
776 );
777 ASSERT_EFI_ERROR (Status);
778 }
779
780
781 /**
782 Variable Driver main entry point. The Variable driver places the 4 EFI
783 runtime services in the EFI System Table and installs arch protocols
784 for variable read and write services being available. It also registers
785 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
786
787 @param[in] ImageHandle The firmware allocated handle for the EFI image.
788 @param[in] SystemTable A pointer to the EFI System Table.
789
790 @retval EFI_SUCCESS Variable service successfully initialized.
791
792 **/
793 EFI_STATUS
794 EFIAPI
795 VariableSmmRuntimeInitialize (
796 IN EFI_HANDLE ImageHandle,
797 IN EFI_SYSTEM_TABLE *SystemTable
798 )
799 {
800 EFI_STATUS Status;
801 VOID *SmmVariableRegistration;
802 VOID *SmmVariableWriteRegistration;
803 EFI_EVENT OnReadyToBootEvent;
804 EFI_EVENT ExitBootServiceEvent;
805
806 EfiInitializeLock (&mVariableServicesLock, TPL_NOTIFY);
807
808 mVariableLock.RequestToLock = VariableLockRequestToLock;
809 Status = gBS->InstallMultipleProtocolInterfaces (
810 &mHandle,
811 &gEdkiiVariableLockProtocolGuid,
812 &mVariableLock,
813 NULL
814 );
815 ASSERT_EFI_ERROR (Status);
816
817 //
818 // Smm variable service is ready
819 //
820 EfiCreateProtocolNotifyEvent (
821 &gEfiSmmVariableProtocolGuid,
822 TPL_CALLBACK,
823 SmmVariableReady,
824 NULL,
825 &SmmVariableRegistration
826 );
827
828 //
829 // Smm Non-Volatile variable write service is ready
830 //
831 EfiCreateProtocolNotifyEvent (
832 &gSmmVariableWriteGuid,
833 TPL_CALLBACK,
834 SmmVariableWriteReady,
835 NULL,
836 &SmmVariableWriteRegistration
837 );
838
839 //
840 // Register the event to reclaim variable for OS usage.
841 //
842 EfiCreateEventReadyToBootEx (
843 TPL_NOTIFY,
844 OnReadyToBoot,
845 NULL,
846 &OnReadyToBootEvent
847 );
848
849 //
850 // Register the event to inform SMM variable that it is at runtime.
851 //
852 gBS->CreateEventEx (
853 EVT_NOTIFY_SIGNAL,
854 TPL_NOTIFY,
855 OnExitBootServices,
856 NULL,
857 &gEfiEventExitBootServicesGuid,
858 &ExitBootServiceEvent
859 );
860
861 //
862 // Register the event to convert the pointer for runtime.
863 //
864 gBS->CreateEventEx (
865 EVT_NOTIFY_SIGNAL,
866 TPL_NOTIFY,
867 VariableAddressChangeEvent,
868 NULL,
869 &gEfiEventVirtualAddressChangeGuid,
870 &mVirtualAddressChangeEvent
871 );
872
873 return EFI_SUCCESS;
874 }
875