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
;
75 if (!IsBufferOutsideMmValid ((UINTN
) CommBuffer
, TempCommBufferSize
)) {
76 DEBUG ((DEBUG_ERROR
, "[%a] - MM Communication buffer in invalid location!\n", __FUNCTION__
));
77 return EFI_ACCESS_DENIED
;
81 // Farm out the job to individual functions based on what was requested.
83 CommParams
= (TPM_NVS_MM_COMM_BUFFER
*) CommBuffer
;
85 switch (CommParams
->Function
) {
86 case TpmNvsMmExchangeInfo
:
87 DEBUG ((DEBUG_VERBOSE
, "[%a] - Function requested: MM_EXCHANGE_NVS_INFO\n", __FUNCTION__
));
88 CommParams
->RegisteredPpSwiValue
= mPpSoftwareSmi
;
89 CommParams
->RegisteredMcSwiValue
= mMcSoftwareSmi
;
90 mTcgNvs
= (TCG_NVS
*) (UINTN
) CommParams
->TargetAddress
;
94 DEBUG ((DEBUG_INFO
, "[%a] - Unknown function %d!\n", __FUNCTION__
, CommParams
->Function
));
95 Status
= EFI_UNSUPPORTED
;
99 CommParams
->ReturnStatus
= (UINT64
) Status
;
104 Software SMI callback for TPM physical presence which is called from ACPI method.
106 Caution: This function may receive untrusted input.
107 Variable and ACPINvs are external input, so this function will validate
108 its data structure to be valid value.
110 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
111 @param[in] Context Points to an optional handler context which was specified when the
112 handler was registered.
113 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
114 be conveyed from a non-SMM environment into an SMM environment.
115 @param[in, out] CommBufferSize The size of the CommBuffer.
117 @retval EFI_SUCCESS The interrupt was handled successfully.
122 PhysicalPresenceCallback (
123 IN EFI_HANDLE DispatchHandle
,
124 IN CONST VOID
*Context
,
125 IN OUT VOID
*CommBuffer
,
126 IN OUT UINTN
*CommBufferSize
129 UINT32 MostRecentRequest
;
131 UINT32 OperationRequest
;
132 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
);
163 Software SMI callback for MemoryClear which is called from ACPI method.
165 Caution: This function may receive untrusted input.
166 Variable and ACPINvs are external input, so this function will validate
167 its data structure to be valid value.
169 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
170 @param[in] Context Points to an optional handler context which was specified when the
171 handler was registered.
172 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
173 be conveyed from a non-SMM environment into an SMM environment.
174 @param[in, out] CommBufferSize The size of the CommBuffer.
176 @retval EFI_SUCCESS The interrupt was handled successfully.
181 MemoryClearCallback (
182 IN EFI_HANDLE DispatchHandle
,
183 IN CONST VOID
*Context
,
184 IN OUT VOID
*CommBuffer
,
185 IN OUT UINTN
*CommBufferSize
192 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_SUCCESS
;
193 if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE
) {
194 MorControl
= (UINT8
) mTcgNvs
->MemoryClear
.Request
;
195 } else if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_PTS_CLEAR_MOR_BIT
) {
196 DataSize
= sizeof (UINT8
);
197 Status
= mSmmVariable
->SmmGetVariable (
198 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
199 &gEfiMemoryOverwriteControlDataGuid
,
204 if (EFI_ERROR (Status
)) {
205 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
206 DEBUG ((DEBUG_ERROR
, "[TPM] Get MOR variable failure! Status = %r\n", Status
));
210 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
;
266 The driver's common initialization routine.
268 It install callbacks for TPM physical presence and MemoryClear, and locate
269 SMM variable to be used in the callback function.
271 @retval EFI_SUCCESS The entry point is executed successfully.
272 @retval Others Some error occurs when executing this entry point.
276 InitializeTcgCommon (
281 EFI_SMM_SW_DISPATCH2_PROTOCOL
*SwDispatch
;
282 EFI_SMM_SW_REGISTER_CONTEXT SwContext
;
283 EFI_HANDLE PpSwHandle
;
284 EFI_HANDLE McSwHandle
;
285 EFI_HANDLE NotifyHandle
;
287 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm20DtpmGuid
)){
288 DEBUG ((DEBUG_ERROR
, "No TPM2 DTPM instance required!\n"));
289 return EFI_UNSUPPORTED
;
292 // Initialize variables first
293 mReadyToLockHandle
= NULL
;
299 // Register a root handler to communicate the NVS region and SMI channel between MM and DXE
300 Status
= gMmst
->MmiHandlerRegister (TpmNvsCommunciate
, &gTpmNvsMmGuid
, &mReadyToLockHandle
);
301 ASSERT_EFI_ERROR (Status
);
302 if (EFI_ERROR (Status
)) {
303 DEBUG ((DEBUG_ERROR
, "[%a] Failed to register NVS communicate as root MM handler - %r!\n", __FUNCTION__
, Status
));
308 // Get the Sw dispatch protocol and register SMI callback functions.
310 Status
= gMmst
->MmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid
, NULL
, (VOID
**)&SwDispatch
);
311 ASSERT_EFI_ERROR (Status
);
312 if (EFI_ERROR (Status
)) {
313 DEBUG ((DEBUG_ERROR
, "[%a] Failed to locate Sw dispatch protocol - %r!\n", __FUNCTION__
, Status
));
317 SwContext
.SwSmiInputValue
= (UINTN
) -1;
318 Status
= SwDispatch
->Register (SwDispatch
, PhysicalPresenceCallback
, &SwContext
, &PpSwHandle
);
319 ASSERT_EFI_ERROR (Status
);
320 if (EFI_ERROR (Status
)) {
321 DEBUG ((DEBUG_ERROR
, "[%a] Failed to register PP callback as SW MM handler - %r!\n", __FUNCTION__
, Status
));
324 mPpSoftwareSmi
= SwContext
.SwSmiInputValue
;
326 SwContext
.SwSmiInputValue
= (UINTN
) -1;
327 Status
= SwDispatch
->Register (SwDispatch
, MemoryClearCallback
, &SwContext
, &McSwHandle
);
328 ASSERT_EFI_ERROR (Status
);
329 if (EFI_ERROR (Status
)) {
330 DEBUG ((DEBUG_ERROR
, "[%a] Failed to register MC callback as SW MM handler - %r!\n", __FUNCTION__
, Status
));
333 mMcSoftwareSmi
= SwContext
.SwSmiInputValue
;
336 // Locate SmmVariableProtocol.
338 Status
= gMmst
->MmLocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
339 ASSERT_EFI_ERROR (Status
);
340 if (EFI_ERROR (Status
)) {
342 DEBUG ((DEBUG_ERROR
, "[%a] Failed to locate SMM variable protocol - %r!\n", __FUNCTION__
, Status
));
346 // Turn off the light before leaving the room... at least, take a remote...
347 Status
= gMmst
->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid
, TcgMmReadyToLock
, &NotifyHandle
);
348 ASSERT_EFI_ERROR (Status
);
349 if (EFI_ERROR (Status
)) {
350 DEBUG ((DEBUG_ERROR
, "[%a] Failed to register ready to lock notification - %r!\n", __FUNCTION__
, Status
));
354 Tcg2NotifyMmReady ();
357 if (EFI_ERROR (Status
)) {
358 // Something is whacked, clean up the mess...
359 if (NotifyHandle
!= NULL
) {
360 gMmst
->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid
, NULL
, &NotifyHandle
);
362 if (McSwHandle
!= NULL
&& SwDispatch
!= NULL
) {
363 SwDispatch
->UnRegister (SwDispatch
, McSwHandle
);
365 if (PpSwHandle
!= NULL
&& SwDispatch
!= NULL
) {
366 SwDispatch
->UnRegister (SwDispatch
, PpSwHandle
);
368 if (mReadyToLockHandle
!= NULL
) {
369 gMmst
->MmiHandlerUnRegister (mReadyToLockHandle
);