Enhance TPM driver to protect TPM physical presence flags.
[mirror_edk2.git] / SecurityPkg / Tcg / TcgSmm / TcgSmm.c
CommitLineData
0c18794e 1/** @file\r
2 It updates TPM items in ACPI table and registers SMI callback\r
3 functions for physical presence and ClearMemory.\r
4\r
dc204d5a
JY
5 Caution: This module requires additional review when modified.\r
6 This driver will have external input - variable and ACPINvs data in SMM mode.\r
7 This external input must be validated carefully to avoid security issue.\r
8\r
9 PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.\r
10\r
ed094569 11Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>\r
0c18794e 12This program and the accompanying materials \r
13are licensed and made available under the terms and conditions of the BSD License \r
14which accompanies this distribution. The full text of the license may be found at \r
15http://opensource.org/licenses/bsd-license.php\r
16\r
17THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
18WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
19\r
20**/\r
21\r
82a1e09c 22#include "TcgSmm.h"\r
0c18794e 23\r
24EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;\r
25TCG_NVS *mTcgNvs;\r
26\r
27/**\r
28 Software SMI callback for TPM physical presence which is called from ACPI method.\r
29\r
dc204d5a
JY
30 Caution: This function may receive untrusted input.\r
31 Variable and ACPINvs are external input, so this function will validate\r
32 its data structure to be valid value.\r
33\r
0c18794e 34 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
35 @param[in] Context 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 successfully.\r
42\r
43**/\r
44EFI_STATUS\r
45EFIAPI\r
46PhysicalPresenceCallback (\r
47 IN EFI_HANDLE DispatchHandle,\r
48 IN CONST VOID *Context,\r
49 IN OUT VOID *CommBuffer,\r
50 IN OUT UINTN *CommBufferSize\r
51 )\r
52{\r
53 EFI_STATUS Status;\r
54 UINTN DataSize;\r
55 EFI_PHYSICAL_PRESENCE PpData;\r
56 UINT8 Flags;\r
57 BOOLEAN RequestConfirmed;\r
58\r
59 //\r
60 // Get the Physical Presence variable\r
61 //\r
62 DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
63 Status = mSmmVariable->SmmGetVariable (\r
64 PHYSICAL_PRESENCE_VARIABLE,\r
65 &gEfiPhysicalPresenceGuid,\r
66 NULL,\r
67 &DataSize,\r
68 &PpData\r
69 );\r
70 if (EFI_ERROR (Status)) {\r
71 return EFI_SUCCESS;\r
72 }\r
73\r
74 DEBUG ((EFI_D_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter));\r
82a1e09c 75 if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {\r
0c18794e 76 mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;\r
77 mTcgNvs->PhysicalPresence.Response = PpData.PPResponse;\r
82a1e09c 78 } else if ((mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS) \r
79 || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {\r
607599bf 80 if (mTcgNvs->PhysicalPresence.Request == PHYSICAL_PRESENCE_SET_OPERATOR_AUTH) {\r
0c18794e 81 //\r
82a1e09c 82 // This command requires UI to prompt user for Auth data.\r
0c18794e 83 //\r
82a1e09c 84 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_NOT_IMPLEMENTED;\r
0c18794e 85 return EFI_SUCCESS;\r
86 }\r
87\r
88 if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {\r
89 PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request;\r
90 DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
91 Status = mSmmVariable->SmmSetVariable (\r
92 PHYSICAL_PRESENCE_VARIABLE,\r
93 &gEfiPhysicalPresenceGuid,\r
94 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
95 DataSize,\r
96 &PpData\r
97 );\r
98 }\r
99\r
100 if (EFI_ERROR (Status)) { \r
82a1e09c 101 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_GENERAL_FAILURE;\r
0c18794e 102 return EFI_SUCCESS;\r
103 }\r
82a1e09c 104 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_SUCCESS;\r
105 } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {\r
ed094569
DG
106 //\r
107 // Get the Physical Presence flags\r
108 //\r
109 DataSize = sizeof (UINT8);\r
110 Status = mSmmVariable->SmmGetVariable (\r
111 PHYSICAL_PRESENCE_FLAGS_VARIABLE,\r
112 &gEfiPhysicalPresenceGuid,\r
113 NULL,\r
114 &DataSize,\r
115 &Flags\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\r
0c18794e 122 RequestConfirmed = FALSE;\r
123\r
124 switch (mTcgNvs->PhysicalPresence.Request) {\r
607599bf 125 case PHYSICAL_PRESENCE_ENABLE:\r
126 case PHYSICAL_PRESENCE_DISABLE:\r
127 case PHYSICAL_PRESENCE_ACTIVATE:\r
128 case PHYSICAL_PRESENCE_DEACTIVATE:\r
129 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE:\r
130 case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE:\r
131 case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_TRUE:\r
132 case PHYSICAL_PRESENCE_SET_OWNER_INSTALL_FALSE:\r
133 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_OWNER_TRUE:\r
134 case PHYSICAL_PRESENCE_DEACTIVATE_DISABLE_OWNER_FALSE:\r
0c18794e 135 if ((Flags & FLAG_NO_PPI_PROVISION) != 0) {\r
136 RequestConfirmed = TRUE;\r
137 }\r
138 break;\r
139\r
607599bf 140 case PHYSICAL_PRESENCE_CLEAR:\r
141 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR:\r
0c18794e 142 if ((Flags & FLAG_NO_PPI_CLEAR) != 0) {\r
143 RequestConfirmed = TRUE;\r
144 }\r
145 break;\r
146\r
607599bf 147 case PHYSICAL_PRESENCE_DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:\r
0c18794e 148 if ((Flags & FLAG_NO_PPI_MAINTENANCE) != 0) {\r
149 RequestConfirmed = TRUE;\r
150 }\r
151 break;\r
152\r
607599bf 153 case PHYSICAL_PRESENCE_ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:\r
154 case PHYSICAL_PRESENCE_CLEAR_ENABLE_ACTIVATE:\r
0c18794e 155 if ((Flags & FLAG_NO_PPI_CLEAR) != 0 && (Flags & FLAG_NO_PPI_PROVISION) != 0) {\r
156 RequestConfirmed = TRUE;\r
157 }\r
158 break; \r
159\r
607599bf 160 case PHYSICAL_PRESENCE_SET_NO_PPI_PROVISION_FALSE:\r
161 case PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:\r
162 case PHYSICAL_PRESENCE_SET_NO_PPI_MAINTENANCE_FALSE:\r
163 case PHYSICAL_PRESENCE_NO_ACTION:\r
0c18794e 164 RequestConfirmed = TRUE;\r
165 break;\r
166\r
607599bf 167 case PHYSICAL_PRESENCE_SET_OPERATOR_AUTH:\r
0c18794e 168 //\r
169 // This command requires UI to prompt user for Auth data\r
0c18794e 170 //\r
82a1e09c 171 mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_NOT_IMPLEMENTED; \r
0c18794e 172 return EFI_SUCCESS;\r
173 }\r
174\r
175 if (RequestConfirmed) {\r
82a1e09c 176 mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_ALLOWED_AND_PPUSER_NOT_REQUIRED;\r
0c18794e 177 } else {\r
82a1e09c 178 mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_ALLOWED_AND_PPUSER_REQUIRED;\r
0c18794e 179 } \r
180 } \r
181\r
182 return EFI_SUCCESS;\r
183}\r
184\r
185\r
186/**\r
187 Software SMI callback for MemoryClear which is called from ACPI method.\r
188\r
dc204d5a
JY
189 Caution: This function may receive untrusted input.\r
190 Variable and ACPINvs are external input, so this function will validate\r
191 its data structure to be valid value.\r
192\r
0c18794e 193 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
194 @param[in] Context Points to an optional handler context which was specified when the\r
195 handler was registered.\r
196 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
197 be conveyed from a non-SMM environment into an SMM environment.\r
198 @param[in, out] CommBufferSize The size of the CommBuffer.\r
199\r
200 @retval EFI_SUCCESS The interrupt was handled successfully.\r
201\r
202**/\r
203EFI_STATUS\r
204EFIAPI\r
205MemoryClearCallback (\r
206 IN EFI_HANDLE DispatchHandle,\r
207 IN CONST VOID *Context,\r
208 IN OUT VOID *CommBuffer,\r
209 IN OUT UINTN *CommBufferSize\r
210 )\r
211{\r
212 EFI_STATUS Status;\r
213 UINTN DataSize;\r
214 UINT8 MorControl;\r
215\r
82a1e09c 216 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;\r
217 if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {\r
0c18794e 218 MorControl = (UINT8) mTcgNvs->MemoryClear.Request;\r
82a1e09c 219 } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {\r
0c18794e 220 DataSize = sizeof (UINT8);\r
221 Status = mSmmVariable->SmmGetVariable (\r
222 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
223 &gEfiMemoryOverwriteControlDataGuid,\r
224 NULL,\r
225 &DataSize,\r
226 &MorControl\r
227 );\r
228 if (EFI_ERROR (Status)) {\r
0c18794e 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
82a1e09c 246 if (EFI_ERROR (Status)) { \r
247 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;\r
248 }\r
0c18794e 249\r
250 return EFI_SUCCESS;\r
251}\r
252\r
253/**\r
254 Find the operation region in TCG ACPI table by given Name and Size,\r
255 and initialize it if the region is found.\r
256\r
257 @param[in, out] Table The TPM item in ACPI table.\r
258 @param[in] Name The name string to find in TPM table.\r
259 @param[in] Size The size of the region to find.\r
260\r
261 @return The allocated address for the found region.\r
262\r
263**/\r
264VOID *\r
265AssignOpRegion (\r
266 EFI_ACPI_DESCRIPTION_HEADER *Table,\r
267 UINT32 Name,\r
268 UINT16 Size\r
269 )\r
270{\r
271 EFI_STATUS Status;\r
272 AML_OP_REGION_32_8 *OpRegion;\r
273 EFI_PHYSICAL_ADDRESS MemoryAddress;\r
274\r
275 MemoryAddress = SIZE_4GB - 1;\r
276\r
277 //\r
278 // Patch some pointers for the ASL code before loading the SSDT.\r
279 //\r
280 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);\r
281 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);\r
282 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {\r
209e6e31 283 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) && \r
0c18794e 284 (OpRegion->NameString == Name) &&\r
0c18794e 285 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&\r
286 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {\r
287\r
288 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);\r
289 ASSERT_EFI_ERROR (Status);\r
290 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);\r
291 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;\r
82a1e09c 292 OpRegion->RegionLen = (UINT8) Size;\r
0c18794e 293 break;\r
294 }\r
295 }\r
296\r
297 return (VOID *) (UINTN) MemoryAddress;\r
298}\r
299\r
300/**\r
301 Initialize and publish TPM items in ACPI table.\r
302\r
303 @retval EFI_SUCCESS The TCG ACPI table is published successfully.\r
304 @retval Others The TCG ACPI table is not published.\r
305\r
306**/\r
307EFI_STATUS\r
308PublishAcpiTable (\r
309 VOID\r
310 )\r
311{\r
312 EFI_STATUS Status;\r
313 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;\r
314 UINTN TableKey;\r
315 EFI_ACPI_DESCRIPTION_HEADER *Table;\r
316 UINTN TableSize;\r
317\r
318 Status = GetSectionFromFv (\r
319 &gEfiCallerIdGuid,\r
320 EFI_SECTION_RAW,\r
321 0,\r
322 (VOID **) &Table,\r
323 &TableSize\r
324 );\r
325 ASSERT_EFI_ERROR (Status);\r
326\r
a332cfd3 327\r
328 //\r
329 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
330 //\r
331 TpmMeasureAndLogData(\r
332 0,\r
333 EV_POST_CODE,\r
334 EV_POSTCODE_INFO_ACPI_DATA,\r
335 ACPI_DATA_LEN,\r
336 Table,\r
337 TableSize\r
338 );\r
339\r
340\r
0c18794e 341 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e'));\r
0f7f6d23 342 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));\r
0c18794e 343 ASSERT (mTcgNvs != NULL);\r
344\r
345 //\r
346 // Publish the TPM ACPI table\r
347 //\r
348 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
349 ASSERT_EFI_ERROR (Status);\r
350\r
351 TableKey = 0;\r
352 Status = AcpiTable->InstallAcpiTable (\r
353 AcpiTable,\r
354 Table,\r
355 TableSize,\r
356 &TableKey\r
357 );\r
358 ASSERT_EFI_ERROR (Status);\r
359\r
360 return Status;\r
361}\r
362\r
363/**\r
364 The driver's entry point.\r
365\r
366 It install callbacks for TPM physical presence and MemoryClear, and locate \r
367 SMM variable to be used in the callback function.\r
368\r
369 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
370 @param[in] SystemTable A pointer to the EFI System Table.\r
371 \r
372 @retval EFI_SUCCESS The entry point is executed successfully.\r
373 @retval Others Some error occurs when executing this entry point.\r
374\r
375**/\r
376EFI_STATUS\r
377EFIAPI\r
378InitializeTcgSmm (\r
379 IN EFI_HANDLE ImageHandle,\r
380 IN EFI_SYSTEM_TABLE *SystemTable\r
381 )\r
382{\r
383 EFI_STATUS Status;\r
384 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;\r
385 EFI_SMM_SW_REGISTER_CONTEXT SwContext;\r
386 EFI_HANDLE SwHandle;\r
387\r
388 Status = PublishAcpiTable ();\r
389 ASSERT_EFI_ERROR (Status);\r
390\r
391 //\r
392 // Get the Sw dispatch protocol and register SMI callback functions.\r
393 //\r
394 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);\r
395 ASSERT_EFI_ERROR (Status);\r
396 SwContext.SwSmiInputValue = (UINTN) -1;\r
397 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);\r
398 ASSERT_EFI_ERROR (Status);\r
399 if (EFI_ERROR (Status)) {\r
400 return Status;\r
401 }\r
402 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
403\r
404 SwContext.SwSmiInputValue = (UINTN) -1;\r
405 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);\r
406 ASSERT_EFI_ERROR (Status);\r
407 if (EFI_ERROR (Status)) {\r
408 return Status;\r
409 }\r
410 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
411 \r
412 //\r
413 // Locate SmmVariableProtocol.\r
414 //\r
415 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);\r
416 ASSERT_EFI_ERROR (Status);\r
417\r
418 return EFI_SUCCESS;\r
419}\r
420\r