2 It updates TPM2 items in ACPI table and registers SMI2 callback
3 functions for Tcg2 physical presence, ClearMemory, and sample
6 Caution: This module requires additional review when modified.
7 This driver will have external input - variable and ACPINvs data in SMM mode.
8 This external input must be validated carefully to avoid security issue.
10 PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
12 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
13 Copyright (c) Microsoft Corporation.
14 SPDX-License-Identifier: BSD-2-Clause-Patent
20 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
= NULL
;
21 TCG_NVS
*mTcgNvs
= NULL
;
24 EFI_HANDLE mReadyToLockHandle
;
27 Communication service SMI Handler entry.
29 This handler takes requests to exchange Mmi channel and Nvs address between MM and DXE.
31 Caution: This function may receive untrusted input.
32 Communicate buffer and buffer size are external input, so this function will do basic validation.
34 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
35 @param[in] RegisterContext Points to an optional handler context which was specified when the
36 handler was registered.
37 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
38 be conveyed from a non-SMM environment into an SMM environment.
39 @param[in, out] CommBufferSize The size of the CommBuffer.
41 @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers
42 should still be called.
43 @retval EFI_UNSUPPORTED An unknown test function was requested.
44 @retval EFI_ACCESS_DENIED Part of the communication buffer lies in an invalid region.
50 IN EFI_HANDLE DispatchHandle
,
51 IN CONST VOID
*RegisterContext
,
52 IN OUT VOID
*CommBuffer
,
53 IN OUT UINTN
*CommBufferSize
57 UINTN TempCommBufferSize
;
58 TPM_NVS_MM_COMM_BUFFER
*CommParams
;
60 DEBUG ((DEBUG_VERBOSE
, "%a()\n", __FUNCTION__
));
63 // If input is invalid, stop processing this SMI
65 if ((CommBuffer
== NULL
) || (CommBufferSize
== NULL
)) {
69 TempCommBufferSize
= *CommBufferSize
;
71 if (TempCommBufferSize
!= sizeof (TPM_NVS_MM_COMM_BUFFER
)) {
72 DEBUG ((DEBUG_ERROR
, "[%a] MM Communication buffer size is invalid for this handler!\n", __FUNCTION__
));
73 return EFI_ACCESS_DENIED
;
76 if (!IsBufferOutsideMmValid ((UINTN
)CommBuffer
, TempCommBufferSize
)) {
77 DEBUG ((DEBUG_ERROR
, "[%a] - MM Communication buffer in invalid location!\n", __FUNCTION__
));
78 return EFI_ACCESS_DENIED
;
82 // Farm out the job to individual functions based on what was requested.
84 CommParams
= (TPM_NVS_MM_COMM_BUFFER
*)CommBuffer
;
86 switch (CommParams
->Function
) {
87 case TpmNvsMmExchangeInfo
:
88 DEBUG ((DEBUG_VERBOSE
, "[%a] - Function requested: MM_EXCHANGE_NVS_INFO\n", __FUNCTION__
));
89 CommParams
->RegisteredPpSwiValue
= mPpSoftwareSmi
;
90 CommParams
->RegisteredMcSwiValue
= mMcSoftwareSmi
;
91 mTcgNvs
= (TCG_NVS
*)(UINTN
)CommParams
->TargetAddress
;
95 DEBUG ((DEBUG_INFO
, "[%a] - Unknown function %d!\n", __FUNCTION__
, CommParams
->Function
));
96 Status
= EFI_UNSUPPORTED
;
100 CommParams
->ReturnStatus
= (UINT64
)Status
;
105 Software SMI callback for TPM physical presence which is called from ACPI method.
107 Caution: This function may receive untrusted input.
108 Variable and ACPINvs are external input, so this function will validate
109 its data structure to be valid value.
111 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
112 @param[in] Context Points to an optional handler context which was specified when the
113 handler was registered.
114 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
115 be conveyed from a non-SMM environment into an SMM environment.
116 @param[in, out] CommBufferSize The size of the CommBuffer.
118 @retval EFI_SUCCESS The interrupt was handled successfully.
123 PhysicalPresenceCallback (
124 IN EFI_HANDLE DispatchHandle
,
125 IN CONST VOID
*Context
,
126 IN OUT VOID
*CommBuffer
,
127 IN OUT UINTN
*CommBufferSize
130 UINT32 MostRecentRequest
;
132 UINT32 OperationRequest
;
133 UINT32 RequestParameter
;
135 if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS
) {
136 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
140 mTcgNvs
->PhysicalPresence
.LastRequest
= MostRecentRequest
;
141 mTcgNvs
->PhysicalPresence
.Response
= Response
;
143 } else if ( (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS
)
144 || (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2
))
146 OperationRequest
= mTcgNvs
->PhysicalPresence
.Request
;
147 RequestParameter
= mTcgNvs
->PhysicalPresence
.RequestParameter
;
148 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
152 mTcgNvs
->PhysicalPresence
.Request
= OperationRequest
;
153 mTcgNvs
->PhysicalPresence
.RequestParameter
= RequestParameter
;
154 } else if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST
) {
155 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs
->PPRequestUserConfirm
);
162 Software SMI callback for MemoryClear which is called from ACPI method.
164 Caution: This function may receive untrusted input.
165 Variable and ACPINvs are external input, so this function will validate
166 its data structure to be valid value.
168 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
169 @param[in] Context Points to an optional handler context which was specified when the
170 handler was registered.
171 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
172 be conveyed from a non-SMM environment into an SMM environment.
173 @param[in, out] CommBufferSize The size of the CommBuffer.
175 @retval EFI_SUCCESS The interrupt was handled successfully.
180 MemoryClearCallback (
181 IN EFI_HANDLE DispatchHandle
,
182 IN CONST VOID
*Context
,
183 IN OUT VOID
*CommBuffer
,
184 IN OUT UINTN
*CommBufferSize
191 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_SUCCESS
;
192 if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE
) {
193 MorControl
= (UINT8
)mTcgNvs
->MemoryClear
.Request
;
194 } else if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_PTS_CLEAR_MOR_BIT
) {
195 DataSize
= sizeof (UINT8
);
196 Status
= mSmmVariable
->SmmGetVariable (
197 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
198 &gEfiMemoryOverwriteControlDataGuid
,
203 if (EFI_ERROR (Status
)) {
204 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
205 DEBUG ((DEBUG_ERROR
, "[TPM] Get MOR variable failure! Status = %r\n", Status
));
209 if (MOR_CLEAR_MEMORY_VALUE (MorControl
) == 0x0) {
213 MorControl
&= ~MOR_CLEAR_MEMORY_BIT_MASK
;
215 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
216 DEBUG ((DEBUG_ERROR
, "[TPM] MOR Parameter error! Parameter = %x\n", mTcgNvs
->MemoryClear
.Parameter
));
220 DataSize
= sizeof (UINT8
);
221 Status
= mSmmVariable
->SmmSetVariable (
222 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
223 &gEfiMemoryOverwriteControlDataGuid
,
224 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
228 if (EFI_ERROR (Status
)) {
229 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
230 DEBUG ((DEBUG_ERROR
, "[TPM] Set MOR variable failure! Status = %r\n", Status
));
237 Notification for SMM ReadyToLock protocol.
239 @param[in] Protocol Points to the protocol's unique identifier.
240 @param[in] Interface Points to the interface instance.
241 @param[in] Handle The handle on which the interface was installed.
243 @retval EFI_SUCCESS Notification runs successfully.
249 IN CONST EFI_GUID
*Protocol
,
256 Status
= EFI_SUCCESS
;
258 if (mReadyToLockHandle
!= NULL
) {
259 Status
= gMmst
->MmiHandlerUnRegister (mReadyToLockHandle
);
260 mReadyToLockHandle
= NULL
;
267 The driver's common initialization routine.
269 It install callbacks for TPM physical presence and MemoryClear, and locate
270 SMM variable to be used in the callback function.
272 @retval EFI_SUCCESS The entry point is executed successfully.
273 @retval Others Some error occurs when executing this entry point.
277 InitializeTcgCommon (
282 EFI_SMM_SW_DISPATCH2_PROTOCOL
*SwDispatch
;
283 EFI_SMM_SW_REGISTER_CONTEXT SwContext
;
284 EFI_HANDLE PpSwHandle
;
285 EFI_HANDLE McSwHandle
;
286 EFI_HANDLE NotifyHandle
;
288 if (!CompareGuid (PcdGetPtr (PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm20DtpmGuid
)) {
289 DEBUG ((DEBUG_ERROR
, "No TPM2 DTPM instance required!\n"));
290 return EFI_UNSUPPORTED
;
293 // Initialize variables first
294 mReadyToLockHandle
= NULL
;
300 // Register a root handler to communicate the NVS region and SMI channel between MM and DXE
301 Status
= gMmst
->MmiHandlerRegister (TpmNvsCommunciate
, &gTpmNvsMmGuid
, &mReadyToLockHandle
);
302 ASSERT_EFI_ERROR (Status
);
303 if (EFI_ERROR (Status
)) {
304 DEBUG ((DEBUG_ERROR
, "[%a] Failed to register NVS communicate as root MM handler - %r!\n", __FUNCTION__
, Status
));
309 // Get the Sw dispatch protocol and register SMI callback functions.
311 Status
= gMmst
->MmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid
, NULL
, (VOID
**)&SwDispatch
);
312 ASSERT_EFI_ERROR (Status
);
313 if (EFI_ERROR (Status
)) {
314 DEBUG ((DEBUG_ERROR
, "[%a] Failed to locate Sw dispatch protocol - %r!\n", __FUNCTION__
, Status
));
318 SwContext
.SwSmiInputValue
= (UINTN
)-1;
319 Status
= SwDispatch
->Register (SwDispatch
, PhysicalPresenceCallback
, &SwContext
, &PpSwHandle
);
320 ASSERT_EFI_ERROR (Status
);
321 if (EFI_ERROR (Status
)) {
322 DEBUG ((DEBUG_ERROR
, "[%a] Failed to register PP callback as SW MM handler - %r!\n", __FUNCTION__
, Status
));
326 mPpSoftwareSmi
= SwContext
.SwSmiInputValue
;
328 SwContext
.SwSmiInputValue
= (UINTN
)-1;
329 Status
= SwDispatch
->Register (SwDispatch
, MemoryClearCallback
, &SwContext
, &McSwHandle
);
330 ASSERT_EFI_ERROR (Status
);
331 if (EFI_ERROR (Status
)) {
332 DEBUG ((DEBUG_ERROR
, "[%a] Failed to register MC callback as SW MM handler - %r!\n", __FUNCTION__
, Status
));
336 mMcSoftwareSmi
= SwContext
.SwSmiInputValue
;
339 // Locate SmmVariableProtocol.
341 Status
= gMmst
->MmLocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
342 ASSERT_EFI_ERROR (Status
);
343 if (EFI_ERROR (Status
)) {
345 DEBUG ((DEBUG_ERROR
, "[%a] Failed to locate SMM variable protocol - %r!\n", __FUNCTION__
, Status
));
349 // Turn off the light before leaving the room... at least, take a remote...
350 Status
= gMmst
->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid
, TcgMmReadyToLock
, &NotifyHandle
);
351 ASSERT_EFI_ERROR (Status
);
352 if (EFI_ERROR (Status
)) {
353 DEBUG ((DEBUG_ERROR
, "[%a] Failed to register ready to lock notification - %r!\n", __FUNCTION__
, Status
));
357 Tcg2NotifyMmReady ();
360 if (EFI_ERROR (Status
)) {
361 // Something is whacked, clean up the mess...
362 if (NotifyHandle
!= NULL
) {
363 gMmst
->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid
, NULL
, &NotifyHandle
);
366 if ((McSwHandle
!= NULL
) && (SwDispatch
!= NULL
)) {
367 SwDispatch
->UnRegister (SwDispatch
, McSwHandle
);
370 if ((PpSwHandle
!= NULL
) && (SwDispatch
!= NULL
)) {
371 SwDispatch
->UnRegister (SwDispatch
, PpSwHandle
);
374 if (mReadyToLockHandle
!= NULL
) {
375 gMmst
->MmiHandlerUnRegister (mReadyToLockHandle
);