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 KQ |
20 | EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable = NULL;\r |
21 | TCG_NVS *mTcgNvs = NULL;\r | |
22 | UINTN mPpSoftwareSmi;\r | |
23 | UINTN mMcSoftwareSmi;\r | |
24 | EFI_HANDLE mReadyToLockHandle;\r | |
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 | |
50 | IN EFI_HANDLE DispatchHandle,\r | |
51 | IN CONST VOID *RegisterContext,\r | |
52 | IN OUT VOID *CommBuffer,\r | |
53 | IN OUT UINTN *CommBufferSize\r | |
54 | )\r | |
55 | {\r | |
56 | EFI_STATUS Status;\r | |
57 | UINTN TempCommBufferSize;\r | |
58 | TPM_NVS_MM_COMM_BUFFER *CommParams;\r | |
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 | |
65 | if (CommBuffer == NULL || CommBufferSize == NULL) {\r | |
66 | return EFI_SUCCESS;\r | |
67 | }\r | |
68 | \r | |
69 | TempCommBufferSize = *CommBufferSize;\r | |
70 | \r | |
71 | if(TempCommBufferSize != sizeof (TPM_NVS_MM_COMM_BUFFER)) {\r | |
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 | |
75 | if (!IsBufferOutsideMmValid ((UINTN) CommBuffer, TempCommBufferSize)) {\r | |
76 | DEBUG ((DEBUG_ERROR, "[%a] - MM Communication buffer in invalid location!\n", __FUNCTION__));\r | |
77 | return EFI_ACCESS_DENIED;\r | |
78 | }\r | |
79 | \r | |
80 | //\r | |
81 | // Farm out the job to individual functions based on what was requested.\r | |
82 | //\r | |
83 | CommParams = (TPM_NVS_MM_COMM_BUFFER*) CommBuffer;\r | |
84 | Status = EFI_SUCCESS;\r | |
85 | switch (CommParams->Function) {\r | |
86 | case TpmNvsMmExchangeInfo:\r | |
87 | DEBUG ((DEBUG_VERBOSE, "[%a] - Function requested: MM_EXCHANGE_NVS_INFO\n", __FUNCTION__));\r | |
88 | CommParams->RegisteredPpSwiValue = mPpSoftwareSmi;\r | |
89 | CommParams->RegisteredMcSwiValue = mMcSoftwareSmi;\r | |
90 | mTcgNvs = (TCG_NVS*) (UINTN) CommParams->TargetAddress;\r | |
91 | break;\r | |
92 | \r | |
93 | default:\r | |
94 | DEBUG ((DEBUG_INFO, "[%a] - Unknown function %d!\n", __FUNCTION__, CommParams->Function));\r | |
95 | Status = EFI_UNSUPPORTED;\r | |
96 | break;\r | |
97 | }\r | |
98 | \r | |
99 | CommParams->ReturnStatus = (UINT64) Status;\r | |
100 | return EFI_SUCCESS;\r | |
101 | }\r | |
1abfa4ce JY |
102 | \r |
103 | /**\r | |
104 | Software SMI callback for TPM physical presence which is called from ACPI method.\r | |
105 | \r | |
106 | Caution: This function may receive untrusted input.\r | |
107 | Variable and ACPINvs are external input, so this function will validate\r | |
108 | its data structure to be valid value.\r | |
109 | \r | |
110 | @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r | |
111 | @param[in] Context Points to an optional handler context which was specified when the\r | |
112 | handler was registered.\r | |
113 | @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r | |
114 | be conveyed from a non-SMM environment into an SMM environment.\r | |
115 | @param[in, out] CommBufferSize The size of the CommBuffer.\r | |
116 | \r | |
117 | @retval EFI_SUCCESS The interrupt was handled successfully.\r | |
118 | \r | |
119 | **/\r | |
120 | EFI_STATUS\r | |
121 | EFIAPI\r | |
122 | PhysicalPresenceCallback (\r | |
123 | IN EFI_HANDLE DispatchHandle,\r | |
124 | IN CONST VOID *Context,\r | |
125 | IN OUT VOID *CommBuffer,\r | |
126 | IN OUT UINTN *CommBufferSize\r | |
127 | )\r | |
128 | {\r | |
129 | UINT32 MostRecentRequest;\r | |
130 | UINT32 Response;\r | |
edb0fda2 ZC |
131 | UINT32 OperationRequest;\r |
132 | UINT32 RequestParameter;\r | |
133 | \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 | |
141 | mTcgNvs->PhysicalPresence.Response = Response;\r | |
142 | return EFI_SUCCESS;\r | |
b3548d32 | 143 | } else if ((mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)\r |
1abfa4ce | 144 | || (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {\r |
edb0fda2 ZC |
145 | \r |
146 | OperationRequest = mTcgNvs->PhysicalPresence.Request;\r | |
147 | RequestParameter = mTcgNvs->PhysicalPresence.RequestParameter;\r | |
148 | mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (\r | |
149 | &OperationRequest,\r | |
150 | &RequestParameter\r | |
1abfa4ce | 151 | );\r |
edb0fda2 ZC |
152 | mTcgNvs->PhysicalPresence.Request = OperationRequest;\r |
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 | |
161 | \r | |
162 | /**\r | |
163 | Software SMI callback for MemoryClear which is called from ACPI method.\r | |
164 | \r | |
165 | Caution: This function may receive untrusted input.\r | |
166 | Variable and ACPINvs are external input, so this function will validate\r | |
167 | its data structure to be valid value.\r | |
168 | \r | |
169 | @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r | |
170 | @param[in] Context Points to an optional handler context which was specified when the\r | |
171 | handler was registered.\r | |
172 | @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r | |
173 | be conveyed from a non-SMM environment into an SMM environment.\r | |
174 | @param[in, out] CommBufferSize The size of the CommBuffer.\r | |
175 | \r | |
176 | @retval EFI_SUCCESS The interrupt was handled successfully.\r | |
177 | \r | |
178 | **/\r | |
179 | EFI_STATUS\r | |
180 | EFIAPI\r | |
181 | MemoryClearCallback (\r | |
182 | IN EFI_HANDLE DispatchHandle,\r | |
183 | IN CONST VOID *Context,\r | |
184 | IN OUT VOID *CommBuffer,\r | |
185 | IN OUT UINTN *CommBufferSize\r | |
186 | )\r | |
187 | {\r | |
188 | EFI_STATUS Status;\r | |
189 | UINTN DataSize;\r | |
190 | UINT8 MorControl;\r | |
191 | \r | |
192 | mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;\r | |
193 | if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {\r | |
194 | MorControl = (UINT8) mTcgNvs->MemoryClear.Request;\r | |
195 | } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {\r | |
196 | DataSize = sizeof (UINT8);\r | |
197 | Status = mSmmVariable->SmmGetVariable (\r | |
198 | MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r | |
199 | &gEfiMemoryOverwriteControlDataGuid,\r | |
200 | NULL,\r | |
201 | &DataSize,\r | |
202 | &MorControl\r | |
203 | );\r | |
204 | if (EFI_ERROR (Status)) {\r | |
205 | mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;\r | |
e905fbb0 | 206 | DEBUG ((DEBUG_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));\r |
1abfa4ce JY |
207 | return EFI_SUCCESS;\r |
208 | }\r | |
209 | \r | |
210 | if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {\r | |
211 | return EFI_SUCCESS;\r | |
212 | }\r | |
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 | |
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 | |
252 | )\r | |
1abfa4ce | 253 | {\r |
3c2dc30d | 254 | EFI_STATUS Status;\r |
a7e2d201 | 255 | \r |
54211ab1 MK |
256 | Status = EFI_SUCCESS;\r |
257 | \r | |
3c2dc30d KQ |
258 | if (mReadyToLockHandle != NULL) {\r |
259 | Status = gMmst->MmiHandlerUnRegister (mReadyToLockHandle);\r | |
260 | mReadyToLockHandle = NULL;\r | |
d967d6d9 | 261 | }\r |
1abfa4ce JY |
262 | return Status;\r |
263 | }\r | |
264 | \r | |
265 | /**\r | |
3c2dc30d | 266 | The driver's common initialization routine.\r |
1abfa4ce | 267 | \r |
b3548d32 | 268 | It install callbacks for TPM physical presence and MemoryClear, and locate\r |
1abfa4ce JY |
269 | SMM variable to be used in the callback function.\r |
270 | \r | |
1abfa4ce JY |
271 | @retval EFI_SUCCESS The entry point is executed successfully.\r |
272 | @retval Others Some error occurs when executing this entry point.\r | |
273 | \r | |
274 | **/\r | |
275 | EFI_STATUS\r | |
3c2dc30d KQ |
276 | InitializeTcgCommon (\r |
277 | VOID\r | |
1abfa4ce JY |
278 | )\r |
279 | {\r | |
280 | EFI_STATUS Status;\r | |
281 | EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;\r | |
282 | EFI_SMM_SW_REGISTER_CONTEXT SwContext;\r | |
3c2dc30d KQ |
283 | EFI_HANDLE PpSwHandle;\r |
284 | EFI_HANDLE McSwHandle;\r | |
285 | EFI_HANDLE NotifyHandle;\r | |
1abfa4ce JY |
286 | \r |
287 | if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){\r | |
e905fbb0 | 288 | DEBUG ((DEBUG_ERROR, "No TPM2 DTPM instance required!\n"));\r |
1abfa4ce JY |
289 | return EFI_UNSUPPORTED;\r |
290 | }\r | |
291 | \r | |
3c2dc30d KQ |
292 | // Initialize variables first\r |
293 | mReadyToLockHandle = NULL;\r | |
294 | SwDispatch = NULL;\r | |
295 | PpSwHandle = NULL;\r | |
296 | McSwHandle = NULL;\r | |
297 | NotifyHandle = NULL;\r | |
298 | \r | |
299 | // Register a root handler to communicate the NVS region and SMI channel between MM and DXE\r | |
300 | Status = gMmst->MmiHandlerRegister (TpmNvsCommunciate, &gTpmNvsMmGuid, &mReadyToLockHandle);\r | |
1abfa4ce | 301 | ASSERT_EFI_ERROR (Status);\r |
3c2dc30d KQ |
302 | if (EFI_ERROR (Status)) {\r |
303 | DEBUG ((DEBUG_ERROR, "[%a] Failed to register NVS communicate as root MM handler - %r!\n", __FUNCTION__, Status));\r | |
304 | goto Cleanup;\r | |
305 | }\r | |
1abfa4ce JY |
306 | \r |
307 | //\r | |
308 | // Get the Sw dispatch protocol and register SMI callback functions.\r | |
309 | //\r | |
e2d6833c | 310 | Status = gMmst->MmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);\r |
1abfa4ce | 311 | ASSERT_EFI_ERROR (Status);\r |
3c2dc30d KQ |
312 | if (EFI_ERROR (Status)) {\r |
313 | DEBUG ((DEBUG_ERROR, "[%a] Failed to locate Sw dispatch protocol - %r!\n", __FUNCTION__, Status));\r | |
314 | goto Cleanup;\r | |
315 | }\r | |
316 | \r | |
1abfa4ce | 317 | SwContext.SwSmiInputValue = (UINTN) -1;\r |
3c2dc30d | 318 | Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &PpSwHandle);\r |
1abfa4ce JY |
319 | ASSERT_EFI_ERROR (Status);\r |
320 | if (EFI_ERROR (Status)) {\r | |
3c2dc30d KQ |
321 | DEBUG ((DEBUG_ERROR, "[%a] Failed to register PP callback as SW MM handler - %r!\n", __FUNCTION__, Status));\r |
322 | goto Cleanup;\r | |
1abfa4ce | 323 | }\r |
3c2dc30d | 324 | mPpSoftwareSmi = SwContext.SwSmiInputValue;\r |
1abfa4ce JY |
325 | \r |
326 | SwContext.SwSmiInputValue = (UINTN) -1;\r | |
3c2dc30d | 327 | Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &McSwHandle);\r |
1abfa4ce JY |
328 | ASSERT_EFI_ERROR (Status);\r |
329 | if (EFI_ERROR (Status)) {\r | |
3c2dc30d KQ |
330 | DEBUG ((DEBUG_ERROR, "[%a] Failed to register MC callback as SW MM handler - %r!\n", __FUNCTION__, Status));\r |
331 | goto Cleanup;\r | |
1abfa4ce | 332 | }\r |
3c2dc30d | 333 | mMcSoftwareSmi = SwContext.SwSmiInputValue;\r |
b3548d32 | 334 | \r |
1abfa4ce JY |
335 | //\r |
336 | // Locate SmmVariableProtocol.\r | |
337 | //\r | |
e2d6833c | 338 | Status = gMmst->MmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);\r |
1abfa4ce | 339 | ASSERT_EFI_ERROR (Status);\r |
3c2dc30d KQ |
340 | if (EFI_ERROR (Status)) {\r |
341 | // Should not happen\r | |
342 | DEBUG ((DEBUG_ERROR, "[%a] Failed to locate SMM variable protocol - %r!\n", __FUNCTION__, Status));\r | |
343 | goto Cleanup;\r | |
344 | }\r | |
1abfa4ce | 345 | \r |
3c2dc30d KQ |
346 | // Turn off the light before leaving the room... at least, take a remote...\r |
347 | Status = gMmst->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid, TcgMmReadyToLock, &NotifyHandle);\r | |
1abfa4ce | 348 | ASSERT_EFI_ERROR (Status);\r |
3c2dc30d KQ |
349 | if (EFI_ERROR (Status)) {\r |
350 | DEBUG ((DEBUG_ERROR, "[%a] Failed to register ready to lock notification - %r!\n", __FUNCTION__, Status));\r | |
351 | goto Cleanup;\r | |
352 | }\r | |
1abfa4ce | 353 | \r |
3c2dc30d | 354 | Tcg2NotifyMmReady ();\r |
1abfa4ce | 355 | \r |
3c2dc30d KQ |
356 | Cleanup:\r |
357 | if (EFI_ERROR (Status)) {\r | |
358 | // Something is whacked, clean up the mess...\r | |
359 | if (NotifyHandle != NULL) {\r | |
360 | gMmst->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid, NULL, &NotifyHandle);\r | |
361 | }\r | |
362 | if (McSwHandle != NULL && SwDispatch != NULL) {\r | |
363 | SwDispatch->UnRegister (SwDispatch, McSwHandle);\r | |
364 | }\r | |
365 | if (PpSwHandle != NULL && SwDispatch != NULL) {\r | |
366 | SwDispatch->UnRegister (SwDispatch, PpSwHandle);\r | |
367 | }\r | |
368 | if (mReadyToLockHandle != NULL) {\r | |
369 | gMmst->MmiHandlerUnRegister (mReadyToLockHandle);\r | |
370 | }\r | |
371 | }\r | |
372 | \r | |
373 | return Status;\r | |
1abfa4ce | 374 | }\r |