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