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