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