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.
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.
11 RuntimeServiceGetVariable() and RuntimeServiceSetVariable() are external API
12 to receive data buffer. The size should be checked carefully.
14 InitCommunicateBuffer() is really function to check the variable data size.
16 Copyright (c) 2010 - 2017, 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
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.
27 #include <Protocol/VariableWrite.h>
28 #include <Protocol/Variable.h>
29 #include <Protocol/SmmCommunication.h>
30 #include <Protocol/SmmVariable.h>
31 #include <Protocol/VariableLock.h>
32 #include <Protocol/VarCheck.h>
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/UefiLib.h>
42 #include <Library/BaseLib.h>
44 #include <Guid/EventGroup.h>
45 #include <Guid/SmmVariableCommon.h>
47 EFI_HANDLE mHandle
= NULL
;
48 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
= NULL
;
49 EFI_EVENT mVirtualAddressChangeEvent
= NULL
;
50 EFI_SMM_COMMUNICATION_PROTOCOL
*mSmmCommunication
= NULL
;
51 UINT8
*mVariableBuffer
= NULL
;
52 UINT8
*mVariableBufferPhysical
= NULL
;
53 UINTN mVariableBufferSize
;
54 UINTN mVariableBufferPayloadSize
;
55 EFI_LOCK mVariableServicesLock
;
56 EDKII_VARIABLE_LOCK_PROTOCOL mVariableLock
;
57 EDKII_VAR_CHECK_PROTOCOL mVarCheck
;
60 SecureBoot Hook for SetVariable.
62 @param[in] VariableName Name of Variable to be found.
63 @param[in] VendorGuid Variable vendor GUID.
69 IN CHAR16
*VariableName
,
70 IN EFI_GUID
*VendorGuid
74 Some Secure Boot Policy Variable may update following other variable changes(SecureBoot follows PK change, etc).
75 Record their initial State when variable write service is ready.
80 RecordSecureBootPolicyVarData(
85 Acquires lock only at boot time. Simply returns at runtime.
87 This is a temperary function that will be removed when
88 EfiAcquireLock() in UefiLib can handle the call in UEFI
89 Runtimer driver in RT phase.
90 It calls EfiAcquireLock() at boot time, and simply returns
93 @param Lock A pointer to the lock to acquire.
97 AcquireLockOnlyAtBootTime (
101 if (!EfiAtRuntime ()) {
102 EfiAcquireLock (Lock
);
107 Releases lock only at boot time. Simply returns at runtime.
109 This is a temperary function which will be removed when
110 EfiReleaseLock() in UefiLib can handle the call in UEFI
111 Runtimer driver in RT phase.
112 It calls EfiReleaseLock() at boot time and simply returns
115 @param Lock A pointer to the lock to release.
119 ReleaseLockOnlyAtBootTime (
123 if (!EfiAtRuntime ()) {
124 EfiReleaseLock (Lock
);
129 Initialize the communicate buffer using DataSize and Function.
131 The communicate size is: SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE +
134 Caution: This function may receive untrusted input.
135 The data size external input, so this function will validate it carefully to avoid buffer overflow.
137 @param[out] DataPtr Points to the data in the communicate buffer.
138 @param[in] DataSize The data size to send to SMM.
139 @param[in] Function The function number to initialize the communicate header.
141 @retval EFI_INVALID_PARAMETER The data size is too big.
142 @retval EFI_SUCCESS Find the specified variable.
146 InitCommunicateBuffer (
147 OUT VOID
**DataPtr OPTIONAL
,
152 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
153 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
156 if (DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
> mVariableBufferSize
) {
157 return EFI_INVALID_PARAMETER
;
160 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
161 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
162 SmmCommunicateHeader
->MessageLength
= DataSize
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
164 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
165 SmmVariableFunctionHeader
->Function
= Function
;
166 if (DataPtr
!= NULL
) {
167 *DataPtr
= SmmVariableFunctionHeader
->Data
;
175 Send the data in communicate buffer to SMM.
177 @param[in] DataSize This size of the function header and the data.
179 @retval EFI_SUCCESS Success is returned from the functin in SMM.
180 @retval Others Failure is returned from the function in SMM.
184 SendCommunicateBuffer (
190 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
191 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
193 CommSize
= DataSize
+ SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
;
194 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, mVariableBufferPhysical
, &CommSize
);
195 ASSERT_EFI_ERROR (Status
);
197 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) mVariableBuffer
;
198 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*)SmmCommunicateHeader
->Data
;
199 return SmmVariableFunctionHeader
->ReturnStatus
;
203 Mark a variable that will become read-only after leaving the DXE phase of execution.
205 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.
206 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.
207 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.
209 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked
210 as pending to be read-only.
211 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.
212 Or VariableName is an empty string.
213 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
214 already been signaled.
215 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.
219 VariableLockRequestToLock (
220 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL
*This
,
221 IN CHAR16
*VariableName
,
222 IN EFI_GUID
*VendorGuid
226 UINTN VariableNameSize
;
228 SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
*VariableToLock
;
230 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
231 return EFI_INVALID_PARAMETER
;
234 VariableNameSize
= StrSize (VariableName
);
235 VariableToLock
= NULL
;
238 // If VariableName exceeds SMM payload limit. Return failure
240 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
)) {
241 return EFI_INVALID_PARAMETER
;
244 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
247 // Init the communicate buffer. The buffer data size is:
248 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
250 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_LOCK_VARIABLE
, Name
) + VariableNameSize
;
251 Status
= InitCommunicateBuffer ((VOID
**) &VariableToLock
, PayloadSize
, SMM_VARIABLE_FUNCTION_LOCK_VARIABLE
);
252 if (EFI_ERROR (Status
)) {
255 ASSERT (VariableToLock
!= NULL
);
257 CopyGuid (&VariableToLock
->Guid
, VendorGuid
);
258 VariableToLock
->NameSize
= VariableNameSize
;
259 CopyMem (VariableToLock
->Name
, VariableName
, VariableToLock
->NameSize
);
264 Status
= SendCommunicateBuffer (PayloadSize
);
267 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
272 Register SetVariable check handler.
274 @param[in] Handler Pointer to check handler.
276 @retval EFI_SUCCESS The SetVariable check handler was registered successfully.
277 @retval EFI_INVALID_PARAMETER Handler is NULL.
278 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
279 already been signaled.
280 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the SetVariable check handler register request.
281 @retval EFI_UNSUPPORTED This interface is not implemented.
282 For example, it is unsupported in VarCheck protocol if both VarCheck and SmmVarCheck protocols are present.
287 VarCheckRegisterSetVariableCheckHandler (
288 IN VAR_CHECK_SET_VARIABLE_CHECK_HANDLER Handler
291 return EFI_UNSUPPORTED
;
295 Variable property set.
297 @param[in] Name Pointer to the variable name.
298 @param[in] Guid Pointer to the vendor GUID.
299 @param[in] VariableProperty Pointer to the input variable property.
301 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was set successfully.
302 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string,
303 or the fields of VariableProperty are not valid.
304 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has
305 already been signaled.
306 @retval EFI_OUT_OF_RESOURCES There is not enough resource for the variable property set request.
311 VarCheckVariablePropertySet (
314 IN VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
318 UINTN VariableNameSize
;
320 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
322 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
323 return EFI_INVALID_PARAMETER
;
326 if (VariableProperty
== NULL
) {
327 return EFI_INVALID_PARAMETER
;
330 if (VariableProperty
->Revision
!= VAR_CHECK_VARIABLE_PROPERTY_REVISION
) {
331 return EFI_INVALID_PARAMETER
;
334 VariableNameSize
= StrSize (Name
);
335 CommVariableProperty
= NULL
;
338 // If VariableName exceeds SMM payload limit. Return failure
340 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
341 return EFI_INVALID_PARAMETER
;
344 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
347 // Init the communicate buffer. The buffer data size is:
348 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
350 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
351 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_SET
);
352 if (EFI_ERROR (Status
)) {
355 ASSERT (CommVariableProperty
!= NULL
);
357 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
358 CopyMem (&CommVariableProperty
->VariableProperty
, VariableProperty
, sizeof (*VariableProperty
));
359 CommVariableProperty
->NameSize
= VariableNameSize
;
360 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
365 Status
= SendCommunicateBuffer (PayloadSize
);
368 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
373 Variable property get.
375 @param[in] Name Pointer to the variable name.
376 @param[in] Guid Pointer to the vendor GUID.
377 @param[out] VariableProperty Pointer to the output variable property.
379 @retval EFI_SUCCESS The property of variable specified by the Name and Guid was got successfully.
380 @retval EFI_INVALID_PARAMETER Name, Guid or VariableProperty is NULL, or Name is an empty string.
381 @retval EFI_NOT_FOUND The property of variable specified by the Name and Guid was not found.
386 VarCheckVariablePropertyGet (
389 OUT VAR_CHECK_VARIABLE_PROPERTY
*VariableProperty
393 UINTN VariableNameSize
;
395 SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
*CommVariableProperty
;
397 if (Name
== NULL
|| Name
[0] == 0 || Guid
== NULL
) {
398 return EFI_INVALID_PARAMETER
;
401 if (VariableProperty
== NULL
) {
402 return EFI_INVALID_PARAMETER
;
405 VariableNameSize
= StrSize (Name
);
406 CommVariableProperty
= NULL
;
409 // If VariableName exceeds SMM payload limit. Return failure
411 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
)) {
412 return EFI_INVALID_PARAMETER
;
415 AcquireLockOnlyAtBootTime (&mVariableServicesLock
);
418 // Init the communicate buffer. The buffer data size is:
419 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
421 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_VAR_CHECK_VARIABLE_PROPERTY
, Name
) + VariableNameSize
;
422 Status
= InitCommunicateBuffer ((VOID
**) &CommVariableProperty
, PayloadSize
, SMM_VARIABLE_FUNCTION_VAR_CHECK_VARIABLE_PROPERTY_GET
);
423 if (EFI_ERROR (Status
)) {
426 ASSERT (CommVariableProperty
!= NULL
);
428 CopyGuid (&CommVariableProperty
->Guid
, Guid
);
429 CommVariableProperty
->NameSize
= VariableNameSize
;
430 CopyMem (CommVariableProperty
->Name
, Name
, CommVariableProperty
->NameSize
);
435 Status
= SendCommunicateBuffer (PayloadSize
);
436 if (Status
== EFI_SUCCESS
) {
437 CopyMem (VariableProperty
, &CommVariableProperty
->VariableProperty
, sizeof (*VariableProperty
));
441 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
446 This code finds variable in storage blocks (Volatile or Non-Volatile).
448 Caution: This function may receive untrusted input.
449 The data size is external input, so this function will validate it carefully to avoid buffer overflow.
451 @param[in] VariableName Name of Variable to be found.
452 @param[in] VendorGuid Variable vendor GUID.
453 @param[out] Attributes Attribute value of the variable found.
454 @param[in, out] DataSize Size of Data found. If size is less than the
455 data, this value contains the required size.
456 @param[out] Data Data pointer.
458 @retval EFI_INVALID_PARAMETER Invalid parameter.
459 @retval EFI_SUCCESS Find the specified variable.
460 @retval EFI_NOT_FOUND Not found.
461 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
466 RuntimeServiceGetVariable (
467 IN CHAR16
*VariableName
,
468 IN EFI_GUID
*VendorGuid
,
469 OUT UINT32
*Attributes OPTIONAL
,
470 IN OUT UINTN
*DataSize
,
476 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
478 UINTN VariableNameSize
;
480 if (VariableName
== NULL
|| VendorGuid
== NULL
|| DataSize
== NULL
) {
481 return EFI_INVALID_PARAMETER
;
484 TempDataSize
= *DataSize
;
485 VariableNameSize
= StrSize (VariableName
);
486 SmmVariableHeader
= NULL
;
489 // If VariableName exceeds SMM payload limit. Return failure
491 if (VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) {
492 return EFI_INVALID_PARAMETER
;
495 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
498 // Init the communicate buffer. The buffer data size is:
499 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
501 if (TempDataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
) {
503 // If output data buffer exceed SMM payload limit. Trim output buffer to SMM payload size
505 TempDataSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
;
507 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ TempDataSize
;
509 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_VARIABLE
);
510 if (EFI_ERROR (Status
)) {
513 ASSERT (SmmVariableHeader
!= NULL
);
515 CopyGuid (&SmmVariableHeader
->Guid
, VendorGuid
);
516 SmmVariableHeader
->DataSize
= TempDataSize
;
517 SmmVariableHeader
->NameSize
= VariableNameSize
;
518 if (Attributes
== NULL
) {
519 SmmVariableHeader
->Attributes
= 0;
521 SmmVariableHeader
->Attributes
= *Attributes
;
523 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
528 Status
= SendCommunicateBuffer (PayloadSize
);
531 // Get data from SMM.
533 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
535 // SMM CommBuffer DataSize can be a trimed value
536 // Only update DataSize when needed
538 *DataSize
= SmmVariableHeader
->DataSize
;
540 if (Attributes
!= NULL
) {
541 *Attributes
= SmmVariableHeader
->Attributes
;
544 if (EFI_ERROR (Status
)) {
549 CopyMem (Data
, (UINT8
*)SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, SmmVariableHeader
->DataSize
);
551 Status
= EFI_INVALID_PARAMETER
;
555 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
561 This code Finds the Next available variable.
563 @param[in, out] VariableNameSize Size of the variable name.
564 @param[in, out] VariableName Pointer to variable name.
565 @param[in, out] VendorGuid Variable Vendor Guid.
567 @retval EFI_INVALID_PARAMETER Invalid parameter.
568 @retval EFI_SUCCESS Find the specified variable.
569 @retval EFI_NOT_FOUND Not found.
570 @retval EFI_BUFFER_TO_SMALL DataSize is too small for the result.
575 RuntimeServiceGetNextVariableName (
576 IN OUT UINTN
*VariableNameSize
,
577 IN OUT CHAR16
*VariableName
,
578 IN OUT EFI_GUID
*VendorGuid
583 SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
*SmmGetNextVariableName
;
584 UINTN OutVariableNameSize
;
585 UINTN InVariableNameSize
;
587 if (VariableNameSize
== NULL
|| VariableName
== NULL
|| VendorGuid
== NULL
) {
588 return EFI_INVALID_PARAMETER
;
591 OutVariableNameSize
= *VariableNameSize
;
592 InVariableNameSize
= StrSize (VariableName
);
593 SmmGetNextVariableName
= NULL
;
596 // If input string exceeds SMM payload limit. Return failure
598 if (InVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
599 return EFI_INVALID_PARAMETER
;
602 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
605 // Init the communicate buffer. The buffer data size is:
606 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
608 if (OutVariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
)) {
610 // If output buffer exceed SMM payload limit. Trim output buffer to SMM payload size
612 OutVariableNameSize
= mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
);
615 // Payload should be Guid + NameSize + MAX of Input & Output buffer
617 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_GET_NEXT_VARIABLE_NAME
, Name
) + MAX (OutVariableNameSize
, InVariableNameSize
);
619 Status
= InitCommunicateBuffer ((VOID
**)&SmmGetNextVariableName
, PayloadSize
, SMM_VARIABLE_FUNCTION_GET_NEXT_VARIABLE_NAME
);
620 if (EFI_ERROR (Status
)) {
623 ASSERT (SmmGetNextVariableName
!= NULL
);
626 // SMM comm buffer->NameSize is buffer size for return string
628 SmmGetNextVariableName
->NameSize
= OutVariableNameSize
;
630 CopyGuid (&SmmGetNextVariableName
->Guid
, VendorGuid
);
634 CopyMem (SmmGetNextVariableName
->Name
, VariableName
, InVariableNameSize
);
635 if (OutVariableNameSize
> InVariableNameSize
) {
636 ZeroMem ((UINT8
*) SmmGetNextVariableName
->Name
+ InVariableNameSize
, OutVariableNameSize
- InVariableNameSize
);
642 Status
= SendCommunicateBuffer (PayloadSize
);
645 // Get data from SMM.
647 if (Status
== EFI_SUCCESS
|| Status
== EFI_BUFFER_TOO_SMALL
) {
649 // SMM CommBuffer NameSize can be a trimed value
650 // Only update VariableNameSize when needed
652 *VariableNameSize
= SmmGetNextVariableName
->NameSize
;
654 if (EFI_ERROR (Status
)) {
658 CopyGuid (VendorGuid
, &SmmGetNextVariableName
->Guid
);
659 CopyMem (VariableName
, SmmGetNextVariableName
->Name
, SmmGetNextVariableName
->NameSize
);
662 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
667 This code sets variable in storage blocks (Volatile or Non-Volatile).
669 Caution: This function may receive untrusted input.
670 The data size and data are external input, so this function will validate it carefully to avoid buffer overflow.
672 @param[in] VariableName Name of Variable to be found.
673 @param[in] VendorGuid Variable vendor GUID.
674 @param[in] Attributes Attribute value of the variable found
675 @param[in] DataSize Size of Data found. If size is less than the
676 data, this value contains the required size.
677 @param[in] Data Data pointer.
679 @retval EFI_INVALID_PARAMETER Invalid parameter.
680 @retval EFI_SUCCESS Set successfully.
681 @retval EFI_OUT_OF_RESOURCES Resource not enough to set variable.
682 @retval EFI_NOT_FOUND Not found.
683 @retval EFI_WRITE_PROTECTED Variable is read-only.
688 RuntimeServiceSetVariable (
689 IN CHAR16
*VariableName
,
690 IN EFI_GUID
*VendorGuid
,
691 IN UINT32 Attributes
,
698 SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
*SmmVariableHeader
;
699 UINTN VariableNameSize
;
702 // Check input parameters.
704 if (VariableName
== NULL
|| VariableName
[0] == 0 || VendorGuid
== NULL
) {
705 return EFI_INVALID_PARAMETER
;
708 if (DataSize
!= 0 && Data
== NULL
) {
709 return EFI_INVALID_PARAMETER
;
712 VariableNameSize
= StrSize (VariableName
);
713 SmmVariableHeader
= NULL
;
716 // If VariableName or DataSize exceeds SMM payload limit. Return failure
718 if ((VariableNameSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
)) ||
719 (DataSize
> mVariableBufferPayloadSize
- OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) - VariableNameSize
)){
720 return EFI_INVALID_PARAMETER
;
723 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
726 // Init the communicate buffer. The buffer data size is:
727 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize.
729 PayloadSize
= OFFSET_OF (SMM_VARIABLE_COMMUNICATE_ACCESS_VARIABLE
, Name
) + VariableNameSize
+ DataSize
;
730 Status
= InitCommunicateBuffer ((VOID
**)&SmmVariableHeader
, PayloadSize
, SMM_VARIABLE_FUNCTION_SET_VARIABLE
);
731 if (EFI_ERROR (Status
)) {
734 ASSERT (SmmVariableHeader
!= NULL
);
736 CopyGuid ((EFI_GUID
*) &SmmVariableHeader
->Guid
, VendorGuid
);
737 SmmVariableHeader
->DataSize
= DataSize
;
738 SmmVariableHeader
->NameSize
= VariableNameSize
;
739 SmmVariableHeader
->Attributes
= Attributes
;
740 CopyMem (SmmVariableHeader
->Name
, VariableName
, SmmVariableHeader
->NameSize
);
741 CopyMem ((UINT8
*) SmmVariableHeader
->Name
+ SmmVariableHeader
->NameSize
, Data
, DataSize
);
746 Status
= SendCommunicateBuffer (PayloadSize
);
749 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
751 if (!EfiAtRuntime ()) {
752 if (!EFI_ERROR (Status
)) {
764 This code returns information about the EFI variables.
766 @param[in] Attributes Attributes bitmask to specify the type of variables
767 on which to return information.
768 @param[out] MaximumVariableStorageSize Pointer to the maximum size of the storage space available
769 for the EFI variables associated with the attributes specified.
770 @param[out] RemainingVariableStorageSize Pointer to the remaining size of the storage space available
771 for EFI variables associated with the attributes specified.
772 @param[out] MaximumVariableSize Pointer to the maximum size of an individual EFI variables
773 associated with the attributes specified.
775 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
776 @retval EFI_SUCCESS Query successfully.
777 @retval EFI_UNSUPPORTED The attribute is not supported on this platform.
782 RuntimeServiceQueryVariableInfo (
783 IN UINT32 Attributes
,
784 OUT UINT64
*MaximumVariableStorageSize
,
785 OUT UINT64
*RemainingVariableStorageSize
,
786 OUT UINT64
*MaximumVariableSize
791 SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
*SmmQueryVariableInfo
;
793 SmmQueryVariableInfo
= NULL
;
795 if(MaximumVariableStorageSize
== NULL
|| RemainingVariableStorageSize
== NULL
|| MaximumVariableSize
== NULL
|| Attributes
== 0) {
796 return EFI_INVALID_PARAMETER
;
799 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
802 // Init the communicate buffer. The buffer data size is:
803 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + PayloadSize;
805 PayloadSize
= sizeof (SMM_VARIABLE_COMMUNICATE_QUERY_VARIABLE_INFO
);
806 Status
= InitCommunicateBuffer ((VOID
**)&SmmQueryVariableInfo
, PayloadSize
, SMM_VARIABLE_FUNCTION_QUERY_VARIABLE_INFO
);
807 if (EFI_ERROR (Status
)) {
810 ASSERT (SmmQueryVariableInfo
!= NULL
);
812 SmmQueryVariableInfo
->Attributes
= Attributes
;
817 Status
= SendCommunicateBuffer (PayloadSize
);
818 if (EFI_ERROR (Status
)) {
823 // Get data from SMM.
825 *MaximumVariableSize
= SmmQueryVariableInfo
->MaximumVariableSize
;
826 *MaximumVariableStorageSize
= SmmQueryVariableInfo
->MaximumVariableStorageSize
;
827 *RemainingVariableStorageSize
= SmmQueryVariableInfo
->RemainingVariableStorageSize
;
830 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
836 Exit Boot Services Event notification handler.
838 Notify SMM variable driver about the event.
840 @param[in] Event Event whose notification function is being invoked.
841 @param[in] Context Pointer to the notification function's context.
852 // Init the communicate buffer. The buffer data size is:
853 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
855 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_EXIT_BOOT_SERVICE
);
860 SendCommunicateBuffer (0);
865 On Ready To Boot Services Event notification handler.
867 Notify SMM variable driver about the event.
869 @param[in] Event Event whose notification function is being invoked
870 @param[in] Context Pointer to the notification function's context
881 // Init the communicate buffer. The buffer data size is:
882 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE.
884 InitCommunicateBuffer (NULL
, 0, SMM_VARIABLE_FUNCTION_READY_TO_BOOT
);
889 SendCommunicateBuffer (0);
891 gBS
->CloseEvent (Event
);
896 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
898 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
899 It convers pointer to new virtual address.
901 @param[in] Event Event whose notification function is being invoked.
902 @param[in] Context Pointer to the notification function's context.
907 VariableAddressChangeEvent (
912 EfiConvertPointer (0x0, (VOID
**) &mVariableBuffer
);
913 EfiConvertPointer (0x0, (VOID
**) &mSmmCommunication
);
917 This code gets variable payload size.
919 @param[out] VariablePayloadSize Output pointer to variable payload size.
921 @retval EFI_SUCCESS Get successfully.
922 @retval Others Get unsuccessfully.
927 GetVariablePayloadSize (
928 OUT UINTN
*VariablePayloadSize
932 SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*SmmGetPayloadSize
;
933 EFI_SMM_COMMUNICATE_HEADER
*SmmCommunicateHeader
;
934 SMM_VARIABLE_COMMUNICATE_HEADER
*SmmVariableFunctionHeader
;
938 SmmGetPayloadSize
= NULL
;
941 if(VariablePayloadSize
== NULL
) {
942 return EFI_INVALID_PARAMETER
;
945 AcquireLockOnlyAtBootTime(&mVariableServicesLock
);
948 // Init the communicate buffer. The buffer data size is:
949 // SMM_COMMUNICATE_HEADER_SIZE + SMM_VARIABLE_COMMUNICATE_HEADER_SIZE + sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE);
951 CommSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
952 CommBuffer
= AllocateZeroPool (CommSize
);
953 if (CommBuffer
== NULL
) {
954 Status
= EFI_OUT_OF_RESOURCES
;
958 SmmCommunicateHeader
= (EFI_SMM_COMMUNICATE_HEADER
*) CommBuffer
;
959 CopyGuid (&SmmCommunicateHeader
->HeaderGuid
, &gEfiSmmVariableProtocolGuid
);
960 SmmCommunicateHeader
->MessageLength
= SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ sizeof (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
);
962 SmmVariableFunctionHeader
= (SMM_VARIABLE_COMMUNICATE_HEADER
*) SmmCommunicateHeader
->Data
;
963 SmmVariableFunctionHeader
->Function
= SMM_VARIABLE_FUNCTION_GET_PAYLOAD_SIZE
;
964 SmmGetPayloadSize
= (SMM_VARIABLE_COMMUNICATE_GET_PAYLOAD_SIZE
*) SmmVariableFunctionHeader
->Data
;
969 Status
= mSmmCommunication
->Communicate (mSmmCommunication
, CommBuffer
, &CommSize
);
970 ASSERT_EFI_ERROR (Status
);
972 Status
= SmmVariableFunctionHeader
->ReturnStatus
;
973 if (EFI_ERROR (Status
)) {
978 // Get data from SMM.
980 *VariablePayloadSize
= SmmGetPayloadSize
->VariablePayloadSize
;
983 if (CommBuffer
!= NULL
) {
984 FreePool (CommBuffer
);
986 ReleaseLockOnlyAtBootTime (&mVariableServicesLock
);
991 Initialize variable service and install Variable Architectural protocol.
993 @param[in] Event Event whose notification function is being invoked.
994 @param[in] Context Pointer to the notification function's context.
1006 Status
= gBS
->LocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
1007 if (EFI_ERROR (Status
)) {
1011 Status
= gBS
->LocateProtocol (&gEfiSmmCommunicationProtocolGuid
, NULL
, (VOID
**) &mSmmCommunication
);
1012 ASSERT_EFI_ERROR (Status
);
1015 // Allocate memory for variable communicate buffer.
1017 Status
= GetVariablePayloadSize (&mVariableBufferPayloadSize
);
1018 ASSERT_EFI_ERROR (Status
);
1019 mVariableBufferSize
= SMM_COMMUNICATE_HEADER_SIZE
+ SMM_VARIABLE_COMMUNICATE_HEADER_SIZE
+ mVariableBufferPayloadSize
;
1020 mVariableBuffer
= AllocateRuntimePool (mVariableBufferSize
);
1021 ASSERT (mVariableBuffer
!= NULL
);
1024 // Save the buffer physical address used for SMM conmunication.
1026 mVariableBufferPhysical
= mVariableBuffer
;
1028 gRT
->GetVariable
= RuntimeServiceGetVariable
;
1029 gRT
->GetNextVariableName
= RuntimeServiceGetNextVariableName
;
1030 gRT
->SetVariable
= RuntimeServiceSetVariable
;
1031 gRT
->QueryVariableInfo
= RuntimeServiceQueryVariableInfo
;
1034 // Install the Variable Architectural Protocol on a new handle.
1036 Status
= gBS
->InstallProtocolInterface (
1038 &gEfiVariableArchProtocolGuid
,
1039 EFI_NATIVE_INTERFACE
,
1042 ASSERT_EFI_ERROR (Status
);
1044 mVariableLock
.RequestToLock
= VariableLockRequestToLock
;
1045 Status
= gBS
->InstallMultipleProtocolInterfaces (
1047 &gEdkiiVariableLockProtocolGuid
,
1051 ASSERT_EFI_ERROR (Status
);
1053 mVarCheck
.RegisterSetVariableCheckHandler
= VarCheckRegisterSetVariableCheckHandler
;
1054 mVarCheck
.VariablePropertySet
= VarCheckVariablePropertySet
;
1055 mVarCheck
.VariablePropertyGet
= VarCheckVariablePropertyGet
;
1056 Status
= gBS
->InstallMultipleProtocolInterfaces (
1058 &gEdkiiVarCheckProtocolGuid
,
1062 ASSERT_EFI_ERROR (Status
);
1064 gBS
->CloseEvent (Event
);
1069 SMM Non-Volatile variable write service is ready notify event handler.
1071 @param[in] Event Event whose notification function is being invoked.
1072 @param[in] Context Pointer to the notification function's context.
1077 SmmVariableWriteReady (
1086 // Check whether the protocol is installed or not.
1088 Status
= gBS
->LocateProtocol (&gSmmVariableWriteGuid
, NULL
, (VOID
**) &ProtocolOps
);
1089 if (EFI_ERROR (Status
)) {
1094 // Some Secure Boot Policy Var (SecureBoot, etc) updates following other
1095 // Secure Boot Policy Variable change. Record their initial value.
1097 RecordSecureBootPolicyVarData();
1099 Status
= gBS
->InstallProtocolInterface (
1101 &gEfiVariableWriteArchProtocolGuid
,
1102 EFI_NATIVE_INTERFACE
,
1105 ASSERT_EFI_ERROR (Status
);
1107 gBS
->CloseEvent (Event
);
1112 Variable Driver main entry point. The Variable driver places the 4 EFI
1113 runtime services in the EFI System Table and installs arch protocols
1114 for variable read and write services being available. It also registers
1115 a notification function for an EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
1117 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1118 @param[in] SystemTable A pointer to the EFI System Table.
1120 @retval EFI_SUCCESS Variable service successfully initialized.
1125 VariableSmmRuntimeInitialize (
1126 IN EFI_HANDLE ImageHandle
,
1127 IN EFI_SYSTEM_TABLE
*SystemTable
1130 VOID
*SmmVariableRegistration
;
1131 VOID
*SmmVariableWriteRegistration
;
1132 EFI_EVENT OnReadyToBootEvent
;
1133 EFI_EVENT ExitBootServiceEvent
;
1134 EFI_EVENT LegacyBootEvent
;
1136 EfiInitializeLock (&mVariableServicesLock
, TPL_NOTIFY
);
1139 // Smm variable service is ready
1141 EfiCreateProtocolNotifyEvent (
1142 &gEfiSmmVariableProtocolGuid
,
1146 &SmmVariableRegistration
1150 // Smm Non-Volatile variable write service is ready
1152 EfiCreateProtocolNotifyEvent (
1153 &gSmmVariableWriteGuid
,
1155 SmmVariableWriteReady
,
1157 &SmmVariableWriteRegistration
1161 // Register the event to reclaim variable for OS usage.
1163 EfiCreateEventReadyToBootEx (
1171 // Register the event to inform SMM variable that it is at runtime.
1173 gBS
->CreateEventEx (
1178 &gEfiEventExitBootServicesGuid
,
1179 &ExitBootServiceEvent
1183 // Register the event to inform SMM variable that it is at runtime for legacy boot.
1184 // Reuse OnExitBootServices() here.
1186 EfiCreateEventLegacyBootEx(
1194 // Register the event to convert the pointer for runtime.
1196 gBS
->CreateEventEx (
1199 VariableAddressChangeEvent
,
1201 &gEfiEventVirtualAddressChangeGuid
,
1202 &mVirtualAddressChangeEvent