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