Add TPM2 support defined in trusted computing group.
[mirror_edk2.git] / SecurityPkg / Tcg / Tcg2Smm / Tcg2Smm.c
CommitLineData
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
12Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
13This program and the accompanying materials \r
14are licensed and made available under the terms and conditions of the BSD License \r
15which accompanies this distribution. The full text of the license may be found at \r
16http://opensource.org/licenses/bsd-license.php\r
17\r
18THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
19WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
20\r
21**/\r
22\r
23#include "Tcg2Smm.h"\r
24\r
25EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = {\r
26 {\r
27 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,\r
28 sizeof (mTpm2AcpiTemplate),\r
29 EFI_TPM2_ACPI_TABLE_REVISION,\r
30 //\r
31 // Compiler initializes the remaining bytes to 0\r
32 // These fields should be filled in in production\r
33 //\r
34 },\r
35 0, // Flags\r
36 0, // Control Area\r
37 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod\r
38};\r
39\r
40EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;\r
41TCG_NVS *mTcgNvs;\r
42\r
43/**\r
44 Software SMI callback for TPM physical presence which is called from ACPI method.\r
45\r
46 Caution: This function may receive untrusted input.\r
47 Variable and ACPINvs are external input, so this function will validate\r
48 its data structure to be valid value.\r
49\r
50 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
51 @param[in] Context Points to an optional handler context which was specified when the\r
52 handler was registered.\r
53 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
54 be conveyed from a non-SMM environment into an SMM environment.\r
55 @param[in, out] CommBufferSize The size of the CommBuffer.\r
56\r
57 @retval EFI_SUCCESS The interrupt was handled successfully.\r
58\r
59**/\r
60EFI_STATUS\r
61EFIAPI\r
62PhysicalPresenceCallback (\r
63 IN EFI_HANDLE DispatchHandle,\r
64 IN CONST VOID *Context,\r
65 IN OUT VOID *CommBuffer,\r
66 IN OUT UINTN *CommBufferSize\r
67 )\r
68{\r
69 UINT32 MostRecentRequest;\r
70 UINT32 Response;\r
71\r
72 if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {\r
73 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (\r
74 &MostRecentRequest,\r
75 &Response\r
76 );\r
77 mTcgNvs->PhysicalPresence.LastRequest = MostRecentRequest;\r
78 mTcgNvs->PhysicalPresence.Response = Response;\r
79 return EFI_SUCCESS;\r
80 } else if ((mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS) \r
81 || (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {\r
82 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (\r
83 mTcgNvs->PhysicalPresence.Request,\r
84 mTcgNvs->PhysicalPresence.RequestParameter\r
85 );\r
86 } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {\r
87 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request);\r
88 } \r
89\r
90 return EFI_SUCCESS;\r
91}\r
92\r
93\r
94/**\r
95 Software SMI callback for MemoryClear which is called from ACPI method.\r
96\r
97 Caution: This function may receive untrusted input.\r
98 Variable and ACPINvs are external input, so this function will validate\r
99 its data structure to be valid value.\r
100\r
101 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
102 @param[in] Context Points to an optional handler context which was specified when the\r
103 handler was registered.\r
104 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
105 be conveyed from a non-SMM environment into an SMM environment.\r
106 @param[in, out] CommBufferSize The size of the CommBuffer.\r
107\r
108 @retval EFI_SUCCESS The interrupt was handled successfully.\r
109\r
110**/\r
111EFI_STATUS\r
112EFIAPI\r
113MemoryClearCallback (\r
114 IN EFI_HANDLE DispatchHandle,\r
115 IN CONST VOID *Context,\r
116 IN OUT VOID *CommBuffer,\r
117 IN OUT UINTN *CommBufferSize\r
118 )\r
119{\r
120 EFI_STATUS Status;\r
121 UINTN DataSize;\r
122 UINT8 MorControl;\r
123\r
124 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;\r
125 if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {\r
126 MorControl = (UINT8) mTcgNvs->MemoryClear.Request;\r
127 } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {\r
128 DataSize = sizeof (UINT8);\r
129 Status = mSmmVariable->SmmGetVariable (\r
130 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
131 &gEfiMemoryOverwriteControlDataGuid,\r
132 NULL,\r
133 &DataSize,\r
134 &MorControl\r
135 );\r
136 if (EFI_ERROR (Status)) {\r
137 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;\r
138 DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));\r
139 return EFI_SUCCESS;\r
140 }\r
141\r
142 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {\r
143 return EFI_SUCCESS;\r
144 }\r
145 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;\r
146 }\r
147\r
148 DataSize = sizeof (UINT8);\r
149 Status = mSmmVariable->SmmSetVariable (\r
150 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
151 &gEfiMemoryOverwriteControlDataGuid,\r
152 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
153 DataSize,\r
154 &MorControl\r
155 );\r
156 if (EFI_ERROR (Status)) { \r
157 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;\r
158 DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));\r
159 }\r
160\r
161 return EFI_SUCCESS;\r
162}\r
163\r
164/**\r
165 Find the operation region in TCG ACPI table by given Name and Size,\r
166 and initialize it if the region is found.\r
167\r
168 @param[in, out] Table The TPM item in ACPI table.\r
169 @param[in] Name The name string to find in TPM table.\r
170 @param[in] Size The size of the region to find.\r
171\r
172 @return The allocated address for the found region.\r
173\r
174**/\r
175VOID *\r
176AssignOpRegion (\r
177 EFI_ACPI_DESCRIPTION_HEADER *Table,\r
178 UINT32 Name,\r
179 UINT16 Size\r
180 )\r
181{\r
182 EFI_STATUS Status;\r
183 AML_OP_REGION_32_8 *OpRegion;\r
184 EFI_PHYSICAL_ADDRESS MemoryAddress;\r
185\r
186 MemoryAddress = SIZE_4GB - 1;\r
187\r
188 //\r
189 // Patch some pointers for the ASL code before loading the SSDT.\r
190 //\r
191 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);\r
192 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);\r
193 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {\r
194 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) && \r
195 (OpRegion->NameString == Name) &&\r
196 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&\r
197 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {\r
198\r
199 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);\r
200 ASSERT_EFI_ERROR (Status);\r
201 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);\r
202 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;\r
203 OpRegion->RegionLen = (UINT8) Size;\r
204 break;\r
205 }\r
206 }\r
207\r
208 return (VOID *) (UINTN) MemoryAddress;\r
209}\r
210\r
211/**\r
212 Initialize and publish TPM items in ACPI table.\r
213\r
214 @retval EFI_SUCCESS The TCG ACPI table is published successfully.\r
215 @retval Others The TCG ACPI table is not published.\r
216\r
217**/\r
218EFI_STATUS\r
219PublishAcpiTable (\r
220 VOID\r
221 )\r
222{\r
223 EFI_STATUS Status;\r
224 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;\r
225 UINTN TableKey;\r
226 EFI_ACPI_DESCRIPTION_HEADER *Table;\r
227 UINTN TableSize;\r
228\r
229 Status = GetSectionFromFv (\r
230 &gEfiCallerIdGuid,\r
231 EFI_SECTION_RAW,\r
232 0,\r
233 (VOID **) &Table,\r
234 &TableSize\r
235 );\r
236 ASSERT_EFI_ERROR (Status);\r
237\r
238\r
239 //\r
240 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
241 //\r
242 TpmMeasureAndLogData(\r
243 0,\r
244 EV_POST_CODE,\r
245 EV_POSTCODE_INFO_ACPI_DATA,\r
246 ACPI_DATA_LEN,\r
247 Table,\r
248 TableSize\r
249 );\r
250\r
251\r
252 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));\r
253 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );\r
254 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));\r
255 ASSERT (mTcgNvs != NULL);\r
256\r
257 //\r
258 // Publish the TPM ACPI table\r
259 //\r
260 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
261 ASSERT_EFI_ERROR (Status);\r
262\r
263 TableKey = 0;\r
264 Status = AcpiTable->InstallAcpiTable (\r
265 AcpiTable,\r
266 Table,\r
267 TableSize,\r
268 &TableKey\r
269 );\r
270 ASSERT_EFI_ERROR (Status);\r
271\r
272 return Status;\r
273}\r
274\r
275/**\r
276 Publish TPM2 ACPI table\r
277\r
278 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.\r
279 @retval Others The TPM2 ACPI table is not published.\r
280\r
281**/\r
282EFI_STATUS\r
283PublishTpm2 (\r
284 VOID\r
285 )\r
286{\r
287 EFI_STATUS Status;\r
288 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;\r
289 UINTN TableKey;\r
290 UINT64 OemTableId;\r
291\r
292 //\r
293 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
294 //\r
295 TpmMeasureAndLogData(\r
296 0,\r
297 EV_POST_CODE,\r
298 EV_POSTCODE_INFO_ACPI_DATA,\r
299 ACPI_DATA_LEN,\r
300 &mTpm2AcpiTemplate,\r
301 sizeof(mTpm2AcpiTemplate)\r
302 );\r
303\r
304 CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));\r
305 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
306 CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));\r
307 mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);\r
308 mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r
309 mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
310\r
311 //\r
312 // Construct ACPI table\r
313 //\r
314 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
315 ASSERT_EFI_ERROR (Status);\r
316\r
317 Status = AcpiTable->InstallAcpiTable (\r
318 AcpiTable,\r
319 &mTpm2AcpiTemplate,\r
320 sizeof(mTpm2AcpiTemplate),\r
321 &TableKey\r
322 );\r
323 ASSERT_EFI_ERROR (Status);\r
324\r
325 return Status;\r
326}\r
327\r
328/**\r
329 The driver's entry point.\r
330\r
331 It install callbacks for TPM physical presence and MemoryClear, and locate \r
332 SMM variable to be used in the callback function.\r
333\r
334 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
335 @param[in] SystemTable A pointer to the EFI System Table.\r
336 \r
337 @retval EFI_SUCCESS The entry point is executed successfully.\r
338 @retval Others Some error occurs when executing this entry point.\r
339\r
340**/\r
341EFI_STATUS\r
342EFIAPI\r
343InitializeTcgSmm (\r
344 IN EFI_HANDLE ImageHandle,\r
345 IN EFI_SYSTEM_TABLE *SystemTable\r
346 )\r
347{\r
348 EFI_STATUS Status;\r
349 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;\r
350 EFI_SMM_SW_REGISTER_CONTEXT SwContext;\r
351 EFI_HANDLE SwHandle;\r
352\r
353 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){\r
354 DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));\r
355 return EFI_UNSUPPORTED;\r
356 }\r
357\r
358 Status = PublishAcpiTable ();\r
359 ASSERT_EFI_ERROR (Status);\r
360\r
361 //\r
362 // Get the Sw dispatch protocol and register SMI callback functions.\r
363 //\r
364 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);\r
365 ASSERT_EFI_ERROR (Status);\r
366 SwContext.SwSmiInputValue = (UINTN) -1;\r
367 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);\r
368 ASSERT_EFI_ERROR (Status);\r
369 if (EFI_ERROR (Status)) {\r
370 return Status;\r
371 }\r
372 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
373\r
374 SwContext.SwSmiInputValue = (UINTN) -1;\r
375 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);\r
376 ASSERT_EFI_ERROR (Status);\r
377 if (EFI_ERROR (Status)) {\r
378 return Status;\r
379 }\r
380 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
381 \r
382 //\r
383 // Locate SmmVariableProtocol.\r
384 //\r
385 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);\r
386 ASSERT_EFI_ERROR (Status);\r
387\r
388 //\r
389 // Set TPM2 ACPI table\r
390 //\r
391 Status = PublishTpm2 ();\r
392 ASSERT_EFI_ERROR (Status);\r
393\r
394\r
395 return EFI_SUCCESS;\r
396}\r
397\r