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