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