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