Fix the return status when physical presence variable and MemoryOverwriteRequestContr...
[mirror_edk2.git] / SecurityPkg / Tcg / TrEESmm / TrEESmm.c
CommitLineData
c1d93242
JY
1/** @file\r
2 It updates TPM2 items in ACPI table and registers SMI2 callback\r
3 functions for TrEE 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
8a8c6c96 12Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>\r
c1d93242
JY
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 "TrEESmm.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 EFI_STATUS Status;\r
70 UINTN DataSize;\r
71 EFI_TREE_PHYSICAL_PRESENCE PpData;\r
72 UINT8 Flags;\r
73 BOOLEAN RequestConfirmed;\r
74\r
75 //\r
76 // Get the Physical Presence variable\r
77 //\r
78 DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);\r
79 Status = mSmmVariable->SmmGetVariable (\r
80 TREE_PHYSICAL_PRESENCE_VARIABLE,\r
81 &gEfiTrEEPhysicalPresenceGuid,\r
82 NULL,\r
83 &DataSize,\r
84 &PpData\r
85 );\r
86 if (EFI_ERROR (Status)) {\r
8a8c6c96
DG
87 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_GENERAL_FAILURE;\r
88 DEBUG ((EFI_D_ERROR, "[TPM] Get PP variable failure! Status = %r\n", Status));\r
c1d93242
JY
89 return EFI_SUCCESS;\r
90 }\r
91\r
92 DEBUG ((EFI_D_INFO, "[TPM2] PP callback, Parameter = %x, Request = %x\n", mTcgNvs->PhysicalPresence.Parameter, mTcgNvs->PhysicalPresence.Request));\r
93\r
94 if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {\r
95 mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;\r
96 mTcgNvs->PhysicalPresence.Response = PpData.PPResponse;\r
97 } else if ((mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS) \r
98 || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {\r
99 if (mTcgNvs->PhysicalPresence.Request > TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {\r
100 //\r
101 // This command requires UI to prompt user for Auth data.\r
102 //\r
103 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_NOT_IMPLEMENTED;\r
104 return EFI_SUCCESS;\r
105 }\r
106\r
107 if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {\r
108 PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request;\r
109 DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);\r
110 Status = mSmmVariable->SmmSetVariable (\r
111 TREE_PHYSICAL_PRESENCE_VARIABLE,\r
112 &gEfiTrEEPhysicalPresenceGuid,\r
113 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
114 DataSize,\r
115 &PpData\r
116 );\r
117 }\r
118\r
119 if (EFI_ERROR (Status)) { \r
120 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_GENERAL_FAILURE;\r
8a8c6c96 121 DEBUG ((EFI_D_ERROR, "[TPM] Set PP variable failure! Status = %r\n", Status));\r
c1d93242
JY
122 return EFI_SUCCESS;\r
123 }\r
124 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_SUCCESS;\r
125 } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {\r
126 //\r
127 // Get the Physical Presence flags\r
128 //\r
129 DataSize = sizeof (UINT8);\r
130 Status = mSmmVariable->SmmGetVariable (\r
131 TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,\r
132 &gEfiTrEEPhysicalPresenceGuid,\r
133 NULL,\r
134 &DataSize,\r
135 &Flags\r
136 );\r
137 if (EFI_ERROR (Status)) {\r
138 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_GENERAL_FAILURE;\r
8a8c6c96 139 DEBUG ((EFI_D_ERROR, "[TPM] Get PP flags failure! Status = %r\n", Status));\r
c1d93242
JY
140 return EFI_SUCCESS;\r
141 }\r
142\r
143 RequestConfirmed = FALSE;\r
144\r
145 switch (mTcgNvs->PhysicalPresence.Request) {\r
146\r
147 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:\r
148 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:\r
149 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:\r
150 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:\r
151 if ((Flags & TREE_FLAG_NO_PPI_CLEAR) != 0) {\r
152 RequestConfirmed = TRUE;\r
153 }\r
154 break;\r
155\r
156 case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:\r
157 RequestConfirmed = TRUE;\r
158 break;\r
159\r
160 case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:\r
161 break;\r
162\r
163 default:\r
164 if (mTcgNvs->PhysicalPresence.Request <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {\r
165 RequestConfirmed = TRUE;\r
166 } else {\r
167 mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_NOT_IMPLEMENTED; \r
168 return EFI_SUCCESS;\r
169 }\r
170 break;\r
171 }\r
172\r
173 if (RequestConfirmed) {\r
174 mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_ALLOWED_AND_PPUSER_NOT_REQUIRED;\r
175 } else {\r
176 mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_ALLOWED_AND_PPUSER_REQUIRED;\r
177 } \r
178 } \r
179\r
180 return EFI_SUCCESS;\r
181}\r
182\r
183\r
184/**\r
185 Software SMI callback for MemoryClear which is called from ACPI method.\r
186\r
187 Caution: This function may receive untrusted input.\r
188 Variable and ACPINvs are external input, so this function will validate\r
189 its data structure to be valid value.\r
190\r
191 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
192 @param[in] Context Points to an optional handler context which was specified when the\r
193 handler was registered.\r
194 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
195 be conveyed from a non-SMM environment into an SMM environment.\r
196 @param[in, out] CommBufferSize The size of the CommBuffer.\r
197\r
198 @retval EFI_SUCCESS The interrupt was handled successfully.\r
199\r
200**/\r
201EFI_STATUS\r
202EFIAPI\r
203MemoryClearCallback (\r
204 IN EFI_HANDLE DispatchHandle,\r
205 IN CONST VOID *Context,\r
206 IN OUT VOID *CommBuffer,\r
207 IN OUT UINTN *CommBufferSize\r
208 )\r
209{\r
210 EFI_STATUS Status;\r
211 UINTN DataSize;\r
212 UINT8 MorControl;\r
213\r
214 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;\r
215 if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {\r
216 MorControl = (UINT8) mTcgNvs->MemoryClear.Request;\r
217 } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {\r
218 DataSize = sizeof (UINT8);\r
219 Status = mSmmVariable->SmmGetVariable (\r
220 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
221 &gEfiMemoryOverwriteControlDataGuid,\r
222 NULL,\r
223 &DataSize,\r
224 &MorControl\r
225 );\r
226 if (EFI_ERROR (Status)) {\r
8a8c6c96
DG
227 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;\r
228 DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));\r
c1d93242
JY
229 return EFI_SUCCESS;\r
230 }\r
231\r
232 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {\r
233 return EFI_SUCCESS;\r
234 }\r
235 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;\r
236 }\r
237\r
238 DataSize = sizeof (UINT8);\r
239 Status = mSmmVariable->SmmSetVariable (\r
240 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
241 &gEfiMemoryOverwriteControlDataGuid,\r
242 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
243 DataSize,\r
244 &MorControl\r
245 );\r
246 if (EFI_ERROR (Status)) { \r
247 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;\r
8a8c6c96 248 DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));\r
c1d93242
JY
249 }\r
250\r
251 return EFI_SUCCESS;\r
252}\r
253\r
254/**\r
255 Find the operation region in TCG ACPI table by given Name and Size,\r
256 and initialize it if the region is found.\r
257\r
258 @param[in, out] Table The TPM item in ACPI table.\r
259 @param[in] Name The name string to find in TPM table.\r
260 @param[in] Size The size of the region to find.\r
261\r
262 @return The allocated address for the found region.\r
263\r
264**/\r
265VOID *\r
266AssignOpRegion (\r
267 EFI_ACPI_DESCRIPTION_HEADER *Table,\r
268 UINT32 Name,\r
269 UINT16 Size\r
270 )\r
271{\r
272 EFI_STATUS Status;\r
273 AML_OP_REGION_32_8 *OpRegion;\r
274 EFI_PHYSICAL_ADDRESS MemoryAddress;\r
275\r
276 MemoryAddress = SIZE_4GB - 1;\r
277\r
278 //\r
279 // Patch some pointers for the ASL code before loading the SSDT.\r
280 //\r
281 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);\r
282 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);\r
283 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {\r
284 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) && \r
285 (OpRegion->NameString == Name) &&\r
286 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&\r
287 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {\r
288\r
289 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);\r
290 ASSERT_EFI_ERROR (Status);\r
291 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);\r
292 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;\r
293 OpRegion->RegionLen = (UINT8) Size;\r
294 break;\r
295 }\r
296 }\r
297\r
298 return (VOID *) (UINTN) MemoryAddress;\r
299}\r
300\r
301/**\r
302 Initialize and publish TPM items in ACPI table.\r
303\r
304 @retval EFI_SUCCESS The TCG ACPI table is published successfully.\r
305 @retval Others The TCG ACPI table is not published.\r
306\r
307**/\r
308EFI_STATUS\r
309PublishAcpiTable (\r
310 VOID\r
311 )\r
312{\r
313 EFI_STATUS Status;\r
314 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;\r
315 UINTN TableKey;\r
316 EFI_ACPI_DESCRIPTION_HEADER *Table;\r
317 UINTN TableSize;\r
318\r
319 Status = GetSectionFromFv (\r
320 &gEfiCallerIdGuid,\r
321 EFI_SECTION_RAW,\r
322 0,\r
323 (VOID **) &Table,\r
324 &TableSize\r
325 );\r
326 ASSERT_EFI_ERROR (Status);\r
327\r
328\r
329 //\r
330 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
331 //\r
332 TpmMeasureAndLogData(\r
333 0,\r
334 EV_POST_CODE,\r
335 EV_POSTCODE_INFO_ACPI_DATA,\r
336 ACPI_DATA_LEN,\r
337 Table,\r
338 TableSize\r
339 );\r
340\r
341\r
342 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));\r
343 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );\r
344 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));\r
345 ASSERT (mTcgNvs != NULL);\r
346\r
347 //\r
348 // Publish the TPM ACPI table\r
349 //\r
350 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
351 ASSERT_EFI_ERROR (Status);\r
352\r
353 TableKey = 0;\r
354 Status = AcpiTable->InstallAcpiTable (\r
355 AcpiTable,\r
356 Table,\r
357 TableSize,\r
358 &TableKey\r
359 );\r
360 ASSERT_EFI_ERROR (Status);\r
361\r
362 return Status;\r
363}\r
364\r
365/**\r
366 Publish TPM2 ACPI table\r
367\r
368 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.\r
369 @retval Others The TPM2 ACPI table is not published.\r
370\r
371**/\r
372EFI_STATUS\r
373PublishTpm2 (\r
374 VOID\r
375 )\r
376{\r
377 EFI_STATUS Status;\r
378 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;\r
379 UINTN TableKey;\r
380 UINT64 OemTableId;\r
381\r
382 //\r
383 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
384 //\r
385 TpmMeasureAndLogData(\r
386 0,\r
387 EV_POST_CODE,\r
388 EV_POSTCODE_INFO_ACPI_DATA,\r
389 ACPI_DATA_LEN,\r
390 &mTpm2AcpiTemplate,\r
391 sizeof(mTpm2AcpiTemplate)\r
392 );\r
393\r
394 CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));\r
395 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
396 CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));\r
397 mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);\r
398 mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);\r
399 mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
400\r
401 //\r
402 // Construct ACPI table\r
403 //\r
404 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
405 ASSERT_EFI_ERROR (Status);\r
406\r
407 Status = AcpiTable->InstallAcpiTable (\r
408 AcpiTable,\r
409 &mTpm2AcpiTemplate,\r
410 sizeof(mTpm2AcpiTemplate),\r
411 &TableKey\r
412 );\r
413 ASSERT_EFI_ERROR (Status);\r
414\r
415 return Status;\r
416}\r
417\r
418/**\r
419 The driver's entry point.\r
420\r
421 It install callbacks for TPM physical presence and MemoryClear, and locate \r
422 SMM variable to be used in the callback function.\r
423\r
424 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
425 @param[in] SystemTable A pointer to the EFI System Table.\r
426 \r
427 @retval EFI_SUCCESS The entry point is executed successfully.\r
428 @retval Others Some error occurs when executing this entry point.\r
429\r
430**/\r
431EFI_STATUS\r
432EFIAPI\r
433InitializeTcgSmm (\r
434 IN EFI_HANDLE ImageHandle,\r
435 IN EFI_SYSTEM_TABLE *SystemTable\r
436 )\r
437{\r
438 EFI_STATUS Status;\r
439 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;\r
440 EFI_SMM_SW_REGISTER_CONTEXT SwContext;\r
441 EFI_HANDLE SwHandle;\r
442\r
443 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){\r
444 DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));\r
445 return EFI_UNSUPPORTED;\r
446 }\r
447\r
448 Status = PublishAcpiTable ();\r
449 ASSERT_EFI_ERROR (Status);\r
450\r
451 //\r
452 // Get the Sw dispatch protocol and register SMI callback functions.\r
453 //\r
454 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);\r
455 ASSERT_EFI_ERROR (Status);\r
456 SwContext.SwSmiInputValue = (UINTN) -1;\r
457 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);\r
458 ASSERT_EFI_ERROR (Status);\r
459 if (EFI_ERROR (Status)) {\r
460 return Status;\r
461 }\r
462 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
463\r
464 SwContext.SwSmiInputValue = (UINTN) -1;\r
465 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);\r
466 ASSERT_EFI_ERROR (Status);\r
467 if (EFI_ERROR (Status)) {\r
468 return Status;\r
469 }\r
470 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
471 \r
472 //\r
473 // Locate SmmVariableProtocol.\r
474 //\r
475 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);\r
476 ASSERT_EFI_ERROR (Status);\r
477\r
478 //\r
479 // Set TPM2 ACPI table\r
480 //\r
481 Status = PublishTpm2 ();\r
482 ASSERT_EFI_ERROR (Status);\r
483\r
484\r
485 return EFI_SUCCESS;\r
486}\r
487\r