Fix ICC9 build break.
[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
5Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>\r
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
16\r
17#include <PiDxe.h>\r
18#include <IndustryStandard/Acpi.h>\r
19#include <Guid/PhysicalPresenceData.h>\r
20#include <Guid/MemoryOverwriteControl.h>\r
21#include <Protocol/SmmSwDispatch2.h>\r
22#include <Protocol/AcpiTable.h>\r
23#include <Protocol/SmmVariable.h>\r
24\r
25#include <Library/BaseLib.h>\r
26#include <Library/BaseMemoryLib.h>\r
27#include <Library/DebugLib.h>\r
28#include <Library/SmmServicesTableLib.h>\r
29#include <Library/UefiDriverEntryPoint.h>\r
30#include <Library/UefiBootServicesTableLib.h>\r
31#include <Library/DxeServicesLib.h>\r
32\r
33//\r
34// AML parsing definitions\r
35//\r
36#define AML_OPREGION_OP 0x80\r
37#define AML_BYTE_PREFIX 0x0A\r
38#define AML_DWORD_PREFIX 0x0C\r
39\r
40#pragma pack(1)\r
41typedef struct {\r
42 UINT8 SoftwareSmi;\r
43 UINT32 Parameter;\r
44 UINT32 Response;\r
45 UINT32 Request;\r
46 UINT32 LastRequest;\r
47 UINT32 ReturnCode;\r
48} PHYSICAL_PRESENCE_NVS;\r
49\r
50typedef struct {\r
51 UINT8 SoftwareSmi;\r
52 UINT32 Parameter;\r
53 UINT32 Request;\r
54} MEMORY_CLEAR_NVS;\r
55\r
56typedef struct {\r
57 PHYSICAL_PRESENCE_NVS PhysicalPresence;\r
58 MEMORY_CLEAR_NVS MemoryClear;\r
59} TCG_NVS;\r
60\r
61typedef struct {\r
62 UINT8 OpRegionOp;\r
63 UINT32 NameString;\r
64 UINT8 RegionSpace;\r
65 UINT8 DWordPrefix;\r
66 UINT32 RegionOffset;\r
67 UINT8 BytePrefix;\r
68 UINT8 RegionLen;\r
69} AML_OP_REGION_32_8;\r
70#pragma pack()\r
71\r
72EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;\r
73TCG_NVS *mTcgNvs;\r
74\r
75/**\r
76 Software SMI callback for TPM physical presence which is called from ACPI method.\r
77\r
78 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
79 @param[in] Context Points to an optional handler context which was specified when the\r
80 handler was registered.\r
81 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
82 be conveyed from a non-SMM environment into an SMM environment.\r
83 @param[in, out] CommBufferSize The size of the CommBuffer.\r
84\r
85 @retval EFI_SUCCESS The interrupt was handled successfully.\r
86\r
87**/\r
88EFI_STATUS\r
89EFIAPI\r
90PhysicalPresenceCallback (\r
91 IN EFI_HANDLE DispatchHandle,\r
92 IN CONST VOID *Context,\r
93 IN OUT VOID *CommBuffer,\r
94 IN OUT UINTN *CommBufferSize\r
95 )\r
96{\r
97 EFI_STATUS Status;\r
98 UINTN DataSize;\r
99 EFI_PHYSICAL_PRESENCE PpData;\r
100 UINT8 Flags;\r
101 BOOLEAN RequestConfirmed;\r
102\r
103 //\r
104 // Get the Physical Presence variable\r
105 //\r
106 DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
107 Status = mSmmVariable->SmmGetVariable (\r
108 PHYSICAL_PRESENCE_VARIABLE,\r
109 &gEfiPhysicalPresenceGuid,\r
110 NULL,\r
111 &DataSize,\r
112 &PpData\r
113 );\r
114 if (EFI_ERROR (Status)) {\r
115 return EFI_SUCCESS;\r
116 }\r
117\r
118 DEBUG ((EFI_D_INFO, "[TPM] PP callback, Parameter = %x\n", mTcgNvs->PhysicalPresence.Parameter));\r
119 if (mTcgNvs->PhysicalPresence.Parameter == 5) {\r
120 //\r
121 // Return TPM Operation Response to OS Environment\r
122 //\r
123 mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;\r
124 mTcgNvs->PhysicalPresence.Response = PpData.PPResponse;\r
125\r
126 } else if ((mTcgNvs->PhysicalPresence.Parameter == 2) || (mTcgNvs->PhysicalPresence.Parameter == 7)) {\r
127 //\r
128 // Submit TPM Operation Request to Pre-OS Environment\r
129 //\r
130\r
131 if (mTcgNvs->PhysicalPresence.Request == SET_OPERATOR_AUTH) {\r
132 //\r
133 // This command requires UI to prompt user for Auth data, NOT implemented.\r
134 //\r
135 mTcgNvs->PhysicalPresence.ReturnCode = 1;\r
136 return EFI_SUCCESS;\r
137 }\r
138\r
139 if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {\r
140 PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request;\r
141 DataSize = sizeof (EFI_PHYSICAL_PRESENCE);\r
142 Status = mSmmVariable->SmmSetVariable (\r
143 PHYSICAL_PRESENCE_VARIABLE,\r
144 &gEfiPhysicalPresenceGuid,\r
145 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
146 DataSize,\r
147 &PpData\r
148 );\r
149 }\r
150\r
151 if (EFI_ERROR (Status)) { \r
152 //\r
153 // General failure.\r
154 //\r
155 mTcgNvs->PhysicalPresence.ReturnCode = 2;\r
156 return EFI_SUCCESS;\r
157 }\r
158 mTcgNvs->PhysicalPresence.ReturnCode = 0;\r
159 } else if (mTcgNvs->PhysicalPresence.Parameter == 8) {\r
160 // \r
161 // Get User Confirmation Status for Operation\r
162 //\r
163 Flags = PpData.Flags; \r
164 RequestConfirmed = FALSE;\r
165\r
166 switch (mTcgNvs->PhysicalPresence.Request) {\r
167 case ENABLE:\r
168 case DISABLE:\r
169 case ACTIVATE:\r
170 case DEACTIVATE:\r
171 case ENABLE_ACTIVATE:\r
172 case DEACTIVATE_DISABLE:\r
173 case SET_OWNER_INSTALL_TRUE:\r
174 case SET_OWNER_INSTALL_FALSE:\r
175 case ENABLE_ACTIVATE_OWNER_TRUE:\r
176 case DEACTIVATE_DISABLE_OWNER_FALSE:\r
177 if ((Flags & FLAG_NO_PPI_PROVISION) != 0) {\r
178 RequestConfirmed = TRUE;\r
179 }\r
180 break;\r
181\r
182 case CLEAR:\r
183 case ENABLE_ACTIVATE_CLEAR:\r
184 if ((Flags & FLAG_NO_PPI_CLEAR) != 0) {\r
185 RequestConfirmed = TRUE;\r
186 }\r
187 break;\r
188\r
189 case DEFERRED_PP_UNOWNERED_FIELD_UPGRADE:\r
190 if ((Flags & FLAG_NO_PPI_MAINTENANCE) != 0) {\r
191 RequestConfirmed = TRUE;\r
192 }\r
193 break;\r
194\r
195 case ENABLE_ACTIVATE_CLEAR_ENABLE_ACTIVATE:\r
196 case CLEAR_ENABLE_ACTIVATE:\r
197 if ((Flags & FLAG_NO_PPI_CLEAR) != 0 && (Flags & FLAG_NO_PPI_PROVISION) != 0) {\r
198 RequestConfirmed = TRUE;\r
199 }\r
200 break; \r
201\r
202 case SET_NO_PPI_PROVISION_FALSE:\r
203 case SET_NO_PPI_CLEAR_FALSE:\r
204 case SET_NO_PPI_MAINTENANCE_FALSE:\r
205 case NO_ACTION:\r
206 RequestConfirmed = TRUE;\r
207 break;\r
208\r
209 case SET_OPERATOR_AUTH:\r
210 //\r
211 // This command requires UI to prompt user for Auth data\r
212 // Here it is NOT implemented\r
213 //\r
214 mTcgNvs->PhysicalPresence.ReturnCode = 0; \r
215 return EFI_SUCCESS;\r
216 }\r
217\r
218 if (RequestConfirmed) {\r
219 //\r
220 // Allowed and physically present user not required \r
221 //\r
222 mTcgNvs->PhysicalPresence.ReturnCode = 4;\r
223 } else {\r
224 //\r
225 // Allowed and physically present user required \r
226 //\r
227 mTcgNvs->PhysicalPresence.ReturnCode = 3;\r
228 } \r
229 } \r
230\r
231 return EFI_SUCCESS;\r
232}\r
233\r
234\r
235/**\r
236 Software SMI callback for MemoryClear which is called from ACPI method.\r
237\r
238 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().\r
239 @param[in] Context Points to an optional handler context which was specified when the\r
240 handler was registered.\r
241 @param[in, out] CommBuffer A pointer to a collection of data in memory that will\r
242 be conveyed from a non-SMM environment into an SMM environment.\r
243 @param[in, out] CommBufferSize The size of the CommBuffer.\r
244\r
245 @retval EFI_SUCCESS The interrupt was handled successfully.\r
246\r
247**/\r
248EFI_STATUS\r
249EFIAPI\r
250MemoryClearCallback (\r
251 IN EFI_HANDLE DispatchHandle,\r
252 IN CONST VOID *Context,\r
253 IN OUT VOID *CommBuffer,\r
254 IN OUT UINTN *CommBufferSize\r
255 )\r
256{\r
257 EFI_STATUS Status;\r
258 UINTN DataSize;\r
259 UINT8 MorControl;\r
260\r
261 if (mTcgNvs->MemoryClear.Parameter == 1) {\r
262 //\r
263 // Called from ACPI _DSM method, save the MOR data to variable.\r
264 //\r
265 MorControl = (UINT8) mTcgNvs->MemoryClear.Request;\r
266 } else if (mTcgNvs->MemoryClear.Parameter == 2) {\r
267 //\r
268 // Called from ACPI _PTS method, setup ClearMemory flags if needed.\r
269 //\r
270 DataSize = sizeof (UINT8);\r
271 Status = mSmmVariable->SmmGetVariable (\r
272 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
273 &gEfiMemoryOverwriteControlDataGuid,\r
274 NULL,\r
275 &DataSize,\r
276 &MorControl\r
277 );\r
278 if (EFI_ERROR (Status)) {\r
279 ASSERT (Status == EFI_NOT_FOUND);\r
280 return EFI_SUCCESS;\r
281 }\r
282\r
283 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {\r
284 return EFI_SUCCESS;\r
285 }\r
286 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;\r
287 }\r
288\r
289 DataSize = sizeof (UINT8);\r
290 Status = mSmmVariable->SmmSetVariable (\r
291 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,\r
292 &gEfiMemoryOverwriteControlDataGuid,\r
293 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
294 DataSize,\r
295 &MorControl\r
296 );\r
297 ASSERT_EFI_ERROR (Status);\r
298\r
299 return EFI_SUCCESS;\r
300}\r
301\r
302/**\r
303 Find the operation region in TCG ACPI table by given Name and Size,\r
304 and initialize it if the region is found.\r
305\r
306 @param[in, out] Table The TPM item in ACPI table.\r
307 @param[in] Name The name string to find in TPM table.\r
308 @param[in] Size The size of the region to find.\r
309\r
310 @return The allocated address for the found region.\r
311\r
312**/\r
313VOID *\r
314AssignOpRegion (\r
315 EFI_ACPI_DESCRIPTION_HEADER *Table,\r
316 UINT32 Name,\r
317 UINT16 Size\r
318 )\r
319{\r
320 EFI_STATUS Status;\r
321 AML_OP_REGION_32_8 *OpRegion;\r
322 EFI_PHYSICAL_ADDRESS MemoryAddress;\r
323\r
324 MemoryAddress = SIZE_4GB - 1;\r
325\r
326 //\r
327 // Patch some pointers for the ASL code before loading the SSDT.\r
328 //\r
329 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);\r
330 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);\r
331 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {\r
332 if ((OpRegion->OpRegionOp == AML_OPREGION_OP) && \r
333 (OpRegion->NameString == Name) &&\r
334 (OpRegion->RegionLen == Size) &&\r
335 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&\r
336 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {\r
337\r
338 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);\r
339 ASSERT_EFI_ERROR (Status);\r
340 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);\r
341 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;\r
342 break;\r
343 }\r
344 }\r
345\r
346 return (VOID *) (UINTN) MemoryAddress;\r
347}\r
348\r
349/**\r
350 Initialize and publish TPM items in ACPI table.\r
351\r
352 @retval EFI_SUCCESS The TCG ACPI table is published successfully.\r
353 @retval Others The TCG ACPI table is not published.\r
354\r
355**/\r
356EFI_STATUS\r
357PublishAcpiTable (\r
358 VOID\r
359 )\r
360{\r
361 EFI_STATUS Status;\r
362 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;\r
363 UINTN TableKey;\r
364 EFI_ACPI_DESCRIPTION_HEADER *Table;\r
365 UINTN TableSize;\r
366\r
367 Status = GetSectionFromFv (\r
368 &gEfiCallerIdGuid,\r
369 EFI_SECTION_RAW,\r
370 0,\r
371 (VOID **) &Table,\r
372 &TableSize\r
373 );\r
374 ASSERT_EFI_ERROR (Status);\r
375\r
376 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'c', 'g', 'T', 'a', 'b', 'l', 'e'));\r
0f7f6d23 377 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));\r
0c18794e 378 ASSERT (mTcgNvs != NULL);\r
379\r
380 //\r
381 // Publish the TPM ACPI table\r
382 //\r
383 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
384 ASSERT_EFI_ERROR (Status);\r
385\r
386 TableKey = 0;\r
387 Status = AcpiTable->InstallAcpiTable (\r
388 AcpiTable,\r
389 Table,\r
390 TableSize,\r
391 &TableKey\r
392 );\r
393 ASSERT_EFI_ERROR (Status);\r
394\r
395 return Status;\r
396}\r
397\r
398/**\r
399 The driver's entry point.\r
400\r
401 It install callbacks for TPM physical presence and MemoryClear, and locate \r
402 SMM variable to be used in the callback function.\r
403\r
404 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
405 @param[in] SystemTable A pointer to the EFI System Table.\r
406 \r
407 @retval EFI_SUCCESS The entry point is executed successfully.\r
408 @retval Others Some error occurs when executing this entry point.\r
409\r
410**/\r
411EFI_STATUS\r
412EFIAPI\r
413InitializeTcgSmm (\r
414 IN EFI_HANDLE ImageHandle,\r
415 IN EFI_SYSTEM_TABLE *SystemTable\r
416 )\r
417{\r
418 EFI_STATUS Status;\r
419 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;\r
420 EFI_SMM_SW_REGISTER_CONTEXT SwContext;\r
421 EFI_HANDLE SwHandle;\r
422\r
423 Status = PublishAcpiTable ();\r
424 ASSERT_EFI_ERROR (Status);\r
425\r
426 //\r
427 // Get the Sw dispatch protocol and register SMI callback functions.\r
428 //\r
429 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);\r
430 ASSERT_EFI_ERROR (Status);\r
431 SwContext.SwSmiInputValue = (UINTN) -1;\r
432 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);\r
433 ASSERT_EFI_ERROR (Status);\r
434 if (EFI_ERROR (Status)) {\r
435 return Status;\r
436 }\r
437 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
438\r
439 SwContext.SwSmiInputValue = (UINTN) -1;\r
440 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);\r
441 ASSERT_EFI_ERROR (Status);\r
442 if (EFI_ERROR (Status)) {\r
443 return Status;\r
444 }\r
445 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
446 \r
447 //\r
448 // Locate SmmVariableProtocol.\r
449 //\r
450 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);\r
451 ASSERT_EFI_ERROR (Status);\r
452\r
453 return EFI_SUCCESS;\r
454}\r
455\r