]>
Commit | Line | Data |
---|---|---|
1abfa4ce JY |
1 | /** @file\r |
2 | It updates TPM2 items in ACPI table and registers SMI2 callback\r | |
3 | functions for Tcg2 physical presence, ClearMemory, and sample\r | |
4 | for dTPM StartMethod.\r | |
5 | \r | |
6 | Caution: This module requires additional review when modified.\r | |
7 | This driver will have external input - variable and ACPINvs data in SMM mode.\r | |
8 | This external input must be validated carefully to avoid security issue.\r | |
9 | \r | |
10 | PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.\r | |
11 | \r | |
c4122dca | 12 | Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r |
3c2dc30d | 13 | Copyright (c) Microsoft Corporation.\r |
289b714b | 14 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
1abfa4ce JY |
15 | \r |
16 | **/\r | |
17 | \r | |
18 | #include "Tcg2Smm.h"\r | |
19 | \r | |
3c2dc30d | 20 | EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;\r |
c411b485 MK |
21 | TCG_NVS *mTcgNvs = NULL;\r |
22 | UINTN mPpSoftwareSmi;\r | |
23 | UINTN mMcSoftwareSmi;\r | |
24 | EFI_HANDLE mReadyToLockHandle;\r | |
3c2dc30d KQ |
25 | \r |
26 | /**\r | |
27 | Communication service SMI Handler entry.\r | |
28 | \r | |
29 | This handler takes requests to exchange Mmi channel and Nvs address between MM and DXE.\r | |
30 | \r | |
31 | Caution: This function may receive untrusted input.\r | |
32 | Communicate buffer and buffer size are external input, so this function will do basic validation.\r | |
33 | \r | |
34 | @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r | |
35 | @param[in] RegisterContext Points to an optional handler context which was specified when the\r | |
36 | handler was registered.\r | |
37 | @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r | |
38 | be conveyed from a non-SMM environment into an SMM environment.\r | |
39 | @param[in, out] CommBufferSize The size of the CommBuffer.\r | |
40 | \r | |
41 | @retval EFI_SUCCESS The interrupt was handled and quiesced. No other handlers\r | |
42 | should still be called.\r | |
43 | @retval EFI_UNSUPPORTED An unknown test function was requested.\r | |
44 | @retval EFI_ACCESS_DENIED Part of the communication buffer lies in an invalid region.\r | |
45 | \r | |
46 | **/\r | |
47 | EFI_STATUS\r | |
48 | EFIAPI\r | |
49 | TpmNvsCommunciate (\r | |
c411b485 MK |
50 | IN EFI_HANDLE DispatchHandle,\r |
51 | IN CONST VOID *RegisterContext,\r | |
52 | IN OUT VOID *CommBuffer,\r | |
53 | IN OUT UINTN *CommBufferSize\r | |
3c2dc30d KQ |
54 | )\r |
55 | {\r | |
c411b485 MK |
56 | EFI_STATUS Status;\r |
57 | UINTN TempCommBufferSize;\r | |
58 | TPM_NVS_MM_COMM_BUFFER *CommParams;\r | |
3c2dc30d KQ |
59 | \r |
60 | DEBUG ((DEBUG_VERBOSE, "%a()\n", __FUNCTION__));\r | |
61 | \r | |
62 | //\r | |
63 | // If input is invalid, stop processing this SMI\r | |
64 | //\r | |
c411b485 | 65 | if ((CommBuffer == NULL) || (CommBufferSize == NULL)) {\r |
3c2dc30d KQ |
66 | return EFI_SUCCESS;\r |
67 | }\r | |
68 | \r | |
69 | TempCommBufferSize = *CommBufferSize;\r | |
70 | \r | |
c411b485 | 71 | if (TempCommBufferSize != sizeof (TPM_NVS_MM_COMM_BUFFER)) {\r |
3c2dc30d KQ |
72 | DEBUG ((DEBUG_ERROR, "[%a] MM Communication buffer size is invalid for this handler!\n", __FUNCTION__));\r |
73 | return EFI_ACCESS_DENIED;\r | |
74 | }\r | |
c411b485 MK |
75 | \r |
76 | if (!IsBufferOutsideMmValid ((UINTN)CommBuffer, TempCommBufferSize)) {\r | |
3c2dc30d KQ |
77 | DEBUG ((DEBUG_ERROR, "[%a] - MM Communication buffer in invalid location!\n", __FUNCTION__));\r |
78 | return EFI_ACCESS_DENIED;\r | |
79 | }\r | |
80 | \r | |
81 | //\r | |
82 | // Farm out the job to individual functions based on what was requested.\r | |
83 | //\r | |
c411b485 MK |
84 | CommParams = (TPM_NVS_MM_COMM_BUFFER *)CommBuffer;\r |
85 | Status = EFI_SUCCESS;\r | |
3c2dc30d KQ |
86 | switch (CommParams->Function) {\r |
87 | case TpmNvsMmExchangeInfo:\r | |
88 | DEBUG ((DEBUG_VERBOSE, "[%a] - Function requested: MM_EXCHANGE_NVS_INFO\n", __FUNCTION__));\r | |
89 | CommParams->RegisteredPpSwiValue = mPpSoftwareSmi;\r | |
90 | CommParams->RegisteredMcSwiValue = mMcSoftwareSmi;\r | |
c411b485 | 91 | mTcgNvs = (TCG_NVS *)(UINTN)CommParams->TargetAddress;\r |
3c2dc30d KQ |
92 | break;\r |
93 | \r | |
94 | default:\r | |
95 | DEBUG ((DEBUG_INFO, "[%a] - Unknown function %d!\n", __FUNCTION__, CommParams->Function));\r | |
96 | Status = EFI_UNSUPPORTED;\r | |
97 | break;\r | |
98 | }\r | |
99 | \r | |
c411b485 | 100 | CommParams->ReturnStatus = (UINT64)Status;\r |
3c2dc30d KQ |
101 | return EFI_SUCCESS;\r |
102 | }\r | |
1abfa4ce JY |
103 | \r |
104 | /**\r | |
105 | Software SMI callback for TPM physical presence which is called from ACPI method.\r | |
106 | \r | |
107 | Caution: This function may receive untrusted input.\r | |
108 | Variable and ACPINvs are external input, so this function will validate\r | |
109 | its data structure to be valid value.\r | |
110 | \r | |
111 | @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r | |
112 | @param[in] Context Points to an optional handler context which was specified when the\r | |
113 | handler was registered.\r | |
114 | @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r | |
115 | be conveyed from a non-SMM environment into an SMM environment.\r | |
116 | @param[in, out] CommBufferSize The size of the CommBuffer.\r | |
117 | \r | |
118 | @retval EFI_SUCCESS The interrupt was handled successfully.\r | |
119 | \r | |
120 | **/\r | |
121 | EFI_STATUS\r | |
122 | EFIAPI\r | |
123 | PhysicalPresenceCallback (\r | |
c411b485 MK |
124 | IN EFI_HANDLE DispatchHandle,\r |
125 | IN CONST VOID *Context,\r | |
126 | IN OUT VOID *CommBuffer,\r | |
127 | IN OUT UINTN *CommBufferSize\r | |
1abfa4ce JY |
128 | )\r |
129 | {\r | |
c411b485 MK |
130 | UINT32 MostRecentRequest;\r |
131 | UINT32 Response;\r | |
132 | UINT32 OperationRequest;\r | |
133 | UINT32 RequestParameter;\r | |
1abfa4ce JY |
134 | \r |
135 | if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {\r | |
136 | mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (\r | |
137 | &MostRecentRequest,\r | |
138 | &Response\r | |
139 | );\r | |
140 | mTcgNvs->PhysicalPresence.LastRequest = MostRecentRequest;\r | |
c411b485 | 141 | mTcgNvs->PhysicalPresence.Response = Response;\r |
1abfa4ce | 142 | return EFI_SUCCESS;\r |
c411b485 MK |
143 | } else if ( (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)\r |
144 | || (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2))\r | |
145 | {\r | |
146 | OperationRequest = mTcgNvs->PhysicalPresence.Request;\r | |
147 | RequestParameter = mTcgNvs->PhysicalPresence.RequestParameter;\r | |
edb0fda2 ZC |
148 | mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (\r |
149 | &OperationRequest,\r | |
150 | &RequestParameter\r | |
1abfa4ce | 151 | );\r |
c411b485 | 152 | mTcgNvs->PhysicalPresence.Request = OperationRequest;\r |
edb0fda2 | 153 | mTcgNvs->PhysicalPresence.RequestParameter = RequestParameter;\r |
1abfa4ce | 154 | } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {\r |
053f31e3 ZC |
155 | mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PPRequestUserConfirm);\r |
156 | }\r | |
1abfa4ce JY |
157 | \r |
158 | return EFI_SUCCESS;\r | |
159 | }\r | |
160 | \r | |
1abfa4ce JY |
161 | /**\r |
162 | Software SMI callback for MemoryClear which is called from ACPI method.\r | |
163 | \r | |
164 | Caution: This function may receive untrusted input.\r | |
165 | Variable and ACPINvs are external input, so this function will validate\r | |
166 | its data structure to be valid value.\r | |
167 | \r | |
168 | @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r | |
169 | @param[in] Context Points to an optional handler context which was specified when the\r | |
170 | handler was registered.\r | |
171 | @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r | |
172 | be conveyed from a non-SMM environment into an SMM environment.\r | |
173 | @param[in, out] CommBufferSize The size of the CommBuffer.\r | |
174 | \r | |
175 | @retval EFI_SUCCESS The interrupt was handled successfully.\r | |
176 | \r | |
177 | **/\r | |
178 | EFI_STATUS\r | |
179 | EFIAPI\r | |
180 | MemoryClearCallback (\r | |
c411b485 MK |
181 | IN EFI_HANDLE DispatchHandle,\r |
182 | IN CONST VOID *Context,\r | |
183 | IN OUT VOID *CommBuffer,\r | |
184 | IN OUT UINTN *CommBufferSize\r | |
1abfa4ce JY |
185 | )\r |
186 | {\r | |
c411b485 MK |
187 | EFI_STATUS Status;\r |
188 | UINTN DataSize;\r | |
189 | UINT8 MorControl;\r | |
1abfa4ce JY |
190 | \r |
191 | mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;\r | |
192 | if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {\r | |
c411b485 | 193 | MorControl = (UINT8)mTcgNvs->MemoryClear.Request;\r |
1abfa4ce JY |
194 | } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {\r |
195 | DataSize = sizeof (UINT8);\r | |
c411b485 MK |
196 | Status = mSmmVariable->SmmGetVariable (\r |
197 | MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r | |
198 | &gEfiMemoryOverwriteControlDataGuid,\r | |
199 | NULL,\r | |
200 | &DataSize,\r | |
201 | &MorControl\r | |
202 | );\r | |
1abfa4ce JY |
203 | if (EFI_ERROR (Status)) {\r |
204 | mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;\r | |
e905fbb0 | 205 | DEBUG ((DEBUG_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));\r |
1abfa4ce JY |
206 | return EFI_SUCCESS;\r |
207 | }\r | |
208 | \r | |
209 | if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {\r | |
210 | return EFI_SUCCESS;\r | |
211 | }\r | |
c411b485 | 212 | \r |
1abfa4ce | 213 | MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;\r |
831bb137 ZC |
214 | } else {\r |
215 | mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;\r | |
e905fbb0 | 216 | DEBUG ((DEBUG_ERROR, "[TPM] MOR Parameter error! Parameter = %x\n", mTcgNvs->MemoryClear.Parameter));\r |
831bb137 | 217 | return EFI_SUCCESS;\r |
1abfa4ce JY |
218 | }\r |
219 | \r | |
220 | DataSize = sizeof (UINT8);\r | |
c411b485 MK |
221 | Status = mSmmVariable->SmmSetVariable (\r |
222 | MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r | |
223 | &gEfiMemoryOverwriteControlDataGuid,\r | |
224 | EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r | |
225 | DataSize,\r | |
226 | &MorControl\r | |
227 | );\r | |
b3548d32 | 228 | if (EFI_ERROR (Status)) {\r |
1abfa4ce | 229 | mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;\r |
e905fbb0 | 230 | DEBUG ((DEBUG_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));\r |
1abfa4ce JY |
231 | }\r |
232 | \r | |
233 | return EFI_SUCCESS;\r | |
234 | }\r | |
235 | \r | |
236 | /**\r | |
3c2dc30d | 237 | Notification for SMM ReadyToLock protocol.\r |
c4122dca | 238 | \r |
3c2dc30d KQ |
239 | @param[in] Protocol Points to the protocol's unique identifier.\r |
240 | @param[in] Interface Points to the interface instance.\r | |
241 | @param[in] Handle The handle on which the interface was installed.\r | |
c4122dca | 242 | \r |
3c2dc30d | 243 | @retval EFI_SUCCESS Notification runs successfully.\r |
c4122dca ZC |
244 | \r |
245 | **/\r | |
246 | EFI_STATUS\r | |
3c2dc30d KQ |
247 | EFIAPI\r |
248 | TcgMmReadyToLock (\r | |
249 | IN CONST EFI_GUID *Protocol,\r | |
250 | IN VOID *Interface,\r | |
251 | IN EFI_HANDLE Handle\r | |
c411b485 | 252 | )\r |
1abfa4ce | 253 | {\r |
c411b485 | 254 | EFI_STATUS Status;\r |
a7e2d201 | 255 | \r |
54211ab1 MK |
256 | Status = EFI_SUCCESS;\r |
257 | \r | |
3c2dc30d | 258 | if (mReadyToLockHandle != NULL) {\r |
c411b485 | 259 | Status = gMmst->MmiHandlerUnRegister (mReadyToLockHandle);\r |
3c2dc30d | 260 | mReadyToLockHandle = NULL;\r |
d967d6d9 | 261 | }\r |
c411b485 | 262 | \r |
1abfa4ce JY |
263 | return Status;\r |
264 | }\r | |
265 | \r | |
266 | /**\r | |
3c2dc30d | 267 | The driver's common initialization routine.\r |
1abfa4ce | 268 | \r |
b3548d32 | 269 | It install callbacks for TPM physical presence and MemoryClear, and locate\r |
1abfa4ce JY |
270 | SMM variable to be used in the callback function.\r |
271 | \r | |
1abfa4ce JY |
272 | @retval EFI_SUCCESS The entry point is executed successfully.\r |
273 | @retval Others Some error occurs when executing this entry point.\r | |
274 | \r | |
275 | **/\r | |
276 | EFI_STATUS\r | |
3c2dc30d KQ |
277 | InitializeTcgCommon (\r |
278 | VOID\r | |
1abfa4ce JY |
279 | )\r |
280 | {\r | |
281 | EFI_STATUS Status;\r | |
282 | EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;\r | |
283 | EFI_SMM_SW_REGISTER_CONTEXT SwContext;\r | |
3c2dc30d KQ |
284 | EFI_HANDLE PpSwHandle;\r |
285 | EFI_HANDLE McSwHandle;\r | |
286 | EFI_HANDLE NotifyHandle;\r | |
1abfa4ce | 287 | \r |
c411b485 | 288 | if (!CompareGuid (PcdGetPtr (PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)) {\r |
e905fbb0 | 289 | DEBUG ((DEBUG_ERROR, "No TPM2 DTPM instance required!\n"));\r |
1abfa4ce JY |
290 | return EFI_UNSUPPORTED;\r |
291 | }\r | |
292 | \r | |
3c2dc30d KQ |
293 | // Initialize variables first\r |
294 | mReadyToLockHandle = NULL;\r | |
c411b485 MK |
295 | SwDispatch = NULL;\r |
296 | PpSwHandle = NULL;\r | |
297 | McSwHandle = NULL;\r | |
298 | NotifyHandle = NULL;\r | |
3c2dc30d KQ |
299 | \r |
300 | // Register a root handler to communicate the NVS region and SMI channel between MM and DXE\r | |
301 | Status = gMmst->MmiHandlerRegister (TpmNvsCommunciate, &gTpmNvsMmGuid, &mReadyToLockHandle);\r | |
1abfa4ce | 302 | ASSERT_EFI_ERROR (Status);\r |
3c2dc30d KQ |
303 | if (EFI_ERROR (Status)) {\r |
304 | DEBUG ((DEBUG_ERROR, "[%a] Failed to register NVS communicate as root MM handler - %r!\n", __FUNCTION__, Status));\r | |
305 | goto Cleanup;\r | |
306 | }\r | |
1abfa4ce JY |
307 | \r |
308 | //\r | |
309 | // Get the Sw dispatch protocol and register SMI callback functions.\r | |
310 | //\r | |
c411b485 | 311 | Status = gMmst->MmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID **)&SwDispatch);\r |
1abfa4ce | 312 | ASSERT_EFI_ERROR (Status);\r |
3c2dc30d KQ |
313 | if (EFI_ERROR (Status)) {\r |
314 | DEBUG ((DEBUG_ERROR, "[%a] Failed to locate Sw dispatch protocol - %r!\n", __FUNCTION__, Status));\r | |
315 | goto Cleanup;\r | |
316 | }\r | |
317 | \r | |
c411b485 MK |
318 | SwContext.SwSmiInputValue = (UINTN)-1;\r |
319 | Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &PpSwHandle);\r | |
1abfa4ce JY |
320 | ASSERT_EFI_ERROR (Status);\r |
321 | if (EFI_ERROR (Status)) {\r | |
3c2dc30d KQ |
322 | DEBUG ((DEBUG_ERROR, "[%a] Failed to register PP callback as SW MM handler - %r!\n", __FUNCTION__, Status));\r |
323 | goto Cleanup;\r | |
1abfa4ce | 324 | }\r |
c411b485 | 325 | \r |
3c2dc30d | 326 | mPpSoftwareSmi = SwContext.SwSmiInputValue;\r |
1abfa4ce | 327 | \r |
c411b485 MK |
328 | SwContext.SwSmiInputValue = (UINTN)-1;\r |
329 | Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &McSwHandle);\r | |
1abfa4ce JY |
330 | ASSERT_EFI_ERROR (Status);\r |
331 | if (EFI_ERROR (Status)) {\r | |
3c2dc30d KQ |
332 | DEBUG ((DEBUG_ERROR, "[%a] Failed to register MC callback as SW MM handler - %r!\n", __FUNCTION__, Status));\r |
333 | goto Cleanup;\r | |
1abfa4ce | 334 | }\r |
c411b485 | 335 | \r |
3c2dc30d | 336 | mMcSoftwareSmi = SwContext.SwSmiInputValue;\r |
b3548d32 | 337 | \r |
1abfa4ce JY |
338 | //\r |
339 | // Locate SmmVariableProtocol.\r | |
340 | //\r | |
c411b485 | 341 | Status = gMmst->MmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID **)&mSmmVariable);\r |
1abfa4ce | 342 | ASSERT_EFI_ERROR (Status);\r |
3c2dc30d KQ |
343 | if (EFI_ERROR (Status)) {\r |
344 | // Should not happen\r | |
345 | DEBUG ((DEBUG_ERROR, "[%a] Failed to locate SMM variable protocol - %r!\n", __FUNCTION__, Status));\r | |
346 | goto Cleanup;\r | |
347 | }\r | |
1abfa4ce | 348 | \r |
3c2dc30d KQ |
349 | // Turn off the light before leaving the room... at least, take a remote...\r |
350 | Status = gMmst->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid, TcgMmReadyToLock, &NotifyHandle);\r | |
1abfa4ce | 351 | ASSERT_EFI_ERROR (Status);\r |
3c2dc30d KQ |
352 | if (EFI_ERROR (Status)) {\r |
353 | DEBUG ((DEBUG_ERROR, "[%a] Failed to register ready to lock notification - %r!\n", __FUNCTION__, Status));\r | |
354 | goto Cleanup;\r | |
355 | }\r | |
1abfa4ce | 356 | \r |
3c2dc30d | 357 | Tcg2NotifyMmReady ();\r |
1abfa4ce | 358 | \r |
3c2dc30d KQ |
359 | Cleanup:\r |
360 | if (EFI_ERROR (Status)) {\r | |
361 | // Something is whacked, clean up the mess...\r | |
362 | if (NotifyHandle != NULL) {\r | |
363 | gMmst->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid, NULL, &NotifyHandle);\r | |
364 | }\r | |
c411b485 MK |
365 | \r |
366 | if ((McSwHandle != NULL) && (SwDispatch != NULL)) {\r | |
3c2dc30d KQ |
367 | SwDispatch->UnRegister (SwDispatch, McSwHandle);\r |
368 | }\r | |
c411b485 MK |
369 | \r |
370 | if ((PpSwHandle != NULL) && (SwDispatch != NULL)) {\r | |
3c2dc30d KQ |
371 | SwDispatch->UnRegister (SwDispatch, PpSwHandle);\r |
372 | }\r | |
c411b485 | 373 | \r |
3c2dc30d KQ |
374 | if (mReadyToLockHandle != NULL) {\r |
375 | gMmst->MmiHandlerUnRegister (mReadyToLockHandle);\r | |
376 | }\r | |
377 | }\r | |
378 | \r | |
379 | return Status;\r | |
1abfa4ce | 380 | }\r |