4826b7916dca3a41a4cf3335c67da7b4fe09dcc9
[mirror_edk2.git] / SecurityPkg / Tcg / TrEESmm / TrEESmm.c
1 /** @file
2 It updates TPM2 items in ACPI table and registers SMI2 callback
3 functions for TrEE physical presence, ClearMemory, and sample
4 for dTPM StartMethod.
5
6 Caution: This module requires additional review when modified.
7 This driver will have external input - variable and ACPINvs data in SMM mode.
8 This external input must be validated carefully to avoid security issue.
9
10 PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
11
12 Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
13 This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
17
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20
21 **/
22
23 #include "TrEESmm.h"
24
25 EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = {
26 {
27 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,
28 sizeof (mTpm2AcpiTemplate),
29 EFI_TPM2_ACPI_TABLE_REVISION,
30 //
31 // Compiler initializes the remaining bytes to 0
32 // These fields should be filled in in production
33 //
34 },
35 0, // Flags
36 0, // Control Area
37 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod
38 };
39
40 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
41 TCG_NVS *mTcgNvs;
42
43 /**
44 Software SMI callback for TPM physical presence which is called from ACPI method.
45
46 Caution: This function may receive untrusted input.
47 Variable and ACPINvs are external input, so this function will validate
48 its data structure to be valid value.
49
50 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
51 @param[in] Context Points to an optional handler context which was specified when the
52 handler was registered.
53 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
54 be conveyed from a non-SMM environment into an SMM environment.
55 @param[in, out] CommBufferSize The size of the CommBuffer.
56
57 @retval EFI_SUCCESS The interrupt was handled successfully.
58
59 **/
60 EFI_STATUS
61 EFIAPI
62 PhysicalPresenceCallback (
63 IN EFI_HANDLE DispatchHandle,
64 IN CONST VOID *Context,
65 IN OUT VOID *CommBuffer,
66 IN OUT UINTN *CommBufferSize
67 )
68 {
69 EFI_STATUS Status;
70 UINTN DataSize;
71 EFI_TREE_PHYSICAL_PRESENCE PpData;
72 UINT8 Flags;
73 BOOLEAN RequestConfirmed;
74
75 //
76 // Get the Physical Presence variable
77 //
78 DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
79 Status = mSmmVariable->SmmGetVariable (
80 TREE_PHYSICAL_PRESENCE_VARIABLE,
81 &gEfiTrEEPhysicalPresenceGuid,
82 NULL,
83 &DataSize,
84 &PpData
85 );
86 if (EFI_ERROR (Status)) {
87 return EFI_SUCCESS;
88 }
89
90 DEBUG ((EFI_D_INFO, "[TPM2] PP callback, Parameter = %x, Request = %x\n", mTcgNvs->PhysicalPresence.Parameter, mTcgNvs->PhysicalPresence.Request));
91
92 if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
93 mTcgNvs->PhysicalPresence.LastRequest = PpData.LastPPRequest;
94 mTcgNvs->PhysicalPresence.Response = PpData.PPResponse;
95 } else if ((mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
96 || (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
97 if (mTcgNvs->PhysicalPresence.Request > TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
98 //
99 // This command requires UI to prompt user for Auth data.
100 //
101 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_NOT_IMPLEMENTED;
102 return EFI_SUCCESS;
103 }
104
105 if (PpData.PPRequest != mTcgNvs->PhysicalPresence.Request) {
106 PpData.PPRequest = (UINT8) mTcgNvs->PhysicalPresence.Request;
107 DataSize = sizeof (EFI_TREE_PHYSICAL_PRESENCE);
108 Status = mSmmVariable->SmmSetVariable (
109 TREE_PHYSICAL_PRESENCE_VARIABLE,
110 &gEfiTrEEPhysicalPresenceGuid,
111 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
112 DataSize,
113 &PpData
114 );
115 }
116
117 if (EFI_ERROR (Status)) {
118 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_GENERAL_FAILURE;
119 return EFI_SUCCESS;
120 }
121 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_SUCCESS;
122 } else if (mTcgNvs->PhysicalPresence.Parameter == ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
123 //
124 // Get the Physical Presence flags
125 //
126 DataSize = sizeof (UINT8);
127 Status = mSmmVariable->SmmGetVariable (
128 TREE_PHYSICAL_PRESENCE_FLAGS_VARIABLE,
129 &gEfiTrEEPhysicalPresenceGuid,
130 NULL,
131 &DataSize,
132 &Flags
133 );
134 if (EFI_ERROR (Status)) {
135 mTcgNvs->PhysicalPresence.ReturnCode = PP_SUBMIT_REQUEST_GENERAL_FAILURE;
136 return EFI_SUCCESS;
137 }
138
139 RequestConfirmed = FALSE;
140
141 switch (mTcgNvs->PhysicalPresence.Request) {
142
143 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR:
144 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_2:
145 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_3:
146 case TREE_PHYSICAL_PRESENCE_CLEAR_CONTROL_CLEAR_4:
147 if ((Flags & TREE_FLAG_NO_PPI_CLEAR) != 0) {
148 RequestConfirmed = TRUE;
149 }
150 break;
151
152 case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_FALSE:
153 RequestConfirmed = TRUE;
154 break;
155
156 case TREE_PHYSICAL_PRESENCE_SET_NO_PPI_CLEAR_TRUE:
157 break;
158
159 default:
160 if (mTcgNvs->PhysicalPresence.Request <= TREE_PHYSICAL_PRESENCE_NO_ACTION_MAX) {
161 RequestConfirmed = TRUE;
162 } else {
163 mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_NOT_IMPLEMENTED;
164 return EFI_SUCCESS;
165 }
166 break;
167 }
168
169 if (RequestConfirmed) {
170 mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_ALLOWED_AND_PPUSER_NOT_REQUIRED;
171 } else {
172 mTcgNvs->PhysicalPresence.ReturnCode = PP_REQUEST_ALLOWED_AND_PPUSER_REQUIRED;
173 }
174 }
175
176 return EFI_SUCCESS;
177 }
178
179
180 /**
181 Software SMI callback for MemoryClear which is called from ACPI method.
182
183 Caution: This function may receive untrusted input.
184 Variable and ACPINvs are external input, so this function will validate
185 its data structure to be valid value.
186
187 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
188 @param[in] Context Points to an optional handler context which was specified when the
189 handler was registered.
190 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
191 be conveyed from a non-SMM environment into an SMM environment.
192 @param[in, out] CommBufferSize The size of the CommBuffer.
193
194 @retval EFI_SUCCESS The interrupt was handled successfully.
195
196 **/
197 EFI_STATUS
198 EFIAPI
199 MemoryClearCallback (
200 IN EFI_HANDLE DispatchHandle,
201 IN CONST VOID *Context,
202 IN OUT VOID *CommBuffer,
203 IN OUT UINTN *CommBufferSize
204 )
205 {
206 EFI_STATUS Status;
207 UINTN DataSize;
208 UINT8 MorControl;
209
210 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
211 if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
212 MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
213 } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
214 DataSize = sizeof (UINT8);
215 Status = mSmmVariable->SmmGetVariable (
216 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
217 &gEfiMemoryOverwriteControlDataGuid,
218 NULL,
219 &DataSize,
220 &MorControl
221 );
222 if (EFI_ERROR (Status)) {
223 return EFI_SUCCESS;
224 }
225
226 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
227 return EFI_SUCCESS;
228 }
229 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
230 }
231
232 DataSize = sizeof (UINT8);
233 Status = mSmmVariable->SmmSetVariable (
234 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
235 &gEfiMemoryOverwriteControlDataGuid,
236 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
237 DataSize,
238 &MorControl
239 );
240 if (EFI_ERROR (Status)) {
241 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
242 }
243
244 return EFI_SUCCESS;
245 }
246
247 /**
248 Find the operation region in TCG ACPI table by given Name and Size,
249 and initialize it if the region is found.
250
251 @param[in, out] Table The TPM item in ACPI table.
252 @param[in] Name The name string to find in TPM table.
253 @param[in] Size The size of the region to find.
254
255 @return The allocated address for the found region.
256
257 **/
258 VOID *
259 AssignOpRegion (
260 EFI_ACPI_DESCRIPTION_HEADER *Table,
261 UINT32 Name,
262 UINT16 Size
263 )
264 {
265 EFI_STATUS Status;
266 AML_OP_REGION_32_8 *OpRegion;
267 EFI_PHYSICAL_ADDRESS MemoryAddress;
268
269 MemoryAddress = SIZE_4GB - 1;
270
271 //
272 // Patch some pointers for the ASL code before loading the SSDT.
273 //
274 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);
275 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);
276 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {
277 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) &&
278 (OpRegion->NameString == Name) &&
279 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
280 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {
281
282 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
283 ASSERT_EFI_ERROR (Status);
284 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
285 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
286 OpRegion->RegionLen = (UINT8) Size;
287 break;
288 }
289 }
290
291 return (VOID *) (UINTN) MemoryAddress;
292 }
293
294 /**
295 Initialize and publish TPM items in ACPI table.
296
297 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
298 @retval Others The TCG ACPI table is not published.
299
300 **/
301 EFI_STATUS
302 PublishAcpiTable (
303 VOID
304 )
305 {
306 EFI_STATUS Status;
307 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
308 UINTN TableKey;
309 EFI_ACPI_DESCRIPTION_HEADER *Table;
310 UINTN TableSize;
311
312 Status = GetSectionFromFv (
313 &gEfiCallerIdGuid,
314 EFI_SECTION_RAW,
315 0,
316 (VOID **) &Table,
317 &TableSize
318 );
319 ASSERT_EFI_ERROR (Status);
320
321
322 //
323 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
324 //
325 TpmMeasureAndLogData(
326 0,
327 EV_POST_CODE,
328 EV_POSTCODE_INFO_ACPI_DATA,
329 ACPI_DATA_LEN,
330 Table,
331 TableSize
332 );
333
334
335 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
336 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
337 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
338 ASSERT (mTcgNvs != NULL);
339
340 //
341 // Publish the TPM ACPI table
342 //
343 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
344 ASSERT_EFI_ERROR (Status);
345
346 TableKey = 0;
347 Status = AcpiTable->InstallAcpiTable (
348 AcpiTable,
349 Table,
350 TableSize,
351 &TableKey
352 );
353 ASSERT_EFI_ERROR (Status);
354
355 return Status;
356 }
357
358 /**
359 Publish TPM2 ACPI table
360
361 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
362 @retval Others The TPM2 ACPI table is not published.
363
364 **/
365 EFI_STATUS
366 PublishTpm2 (
367 VOID
368 )
369 {
370 EFI_STATUS Status;
371 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
372 UINTN TableKey;
373 UINT64 OemTableId;
374
375 //
376 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
377 //
378 TpmMeasureAndLogData(
379 0,
380 EV_POST_CODE,
381 EV_POSTCODE_INFO_ACPI_DATA,
382 ACPI_DATA_LEN,
383 &mTpm2AcpiTemplate,
384 sizeof(mTpm2AcpiTemplate)
385 );
386
387 CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));
388 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
389 CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
390 mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
391 mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
392 mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
393
394 //
395 // Construct ACPI table
396 //
397 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
398 ASSERT_EFI_ERROR (Status);
399
400 Status = AcpiTable->InstallAcpiTable (
401 AcpiTable,
402 &mTpm2AcpiTemplate,
403 sizeof(mTpm2AcpiTemplate),
404 &TableKey
405 );
406 ASSERT_EFI_ERROR (Status);
407
408 return Status;
409 }
410
411 /**
412 The driver's entry point.
413
414 It install callbacks for TPM physical presence and MemoryClear, and locate
415 SMM variable to be used in the callback function.
416
417 @param[in] ImageHandle The firmware allocated handle for the EFI image.
418 @param[in] SystemTable A pointer to the EFI System Table.
419
420 @retval EFI_SUCCESS The entry point is executed successfully.
421 @retval Others Some error occurs when executing this entry point.
422
423 **/
424 EFI_STATUS
425 EFIAPI
426 InitializeTcgSmm (
427 IN EFI_HANDLE ImageHandle,
428 IN EFI_SYSTEM_TABLE *SystemTable
429 )
430 {
431 EFI_STATUS Status;
432 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
433 EFI_SMM_SW_REGISTER_CONTEXT SwContext;
434 EFI_HANDLE SwHandle;
435
436 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){
437 DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));
438 return EFI_UNSUPPORTED;
439 }
440
441 Status = PublishAcpiTable ();
442 ASSERT_EFI_ERROR (Status);
443
444 //
445 // Get the Sw dispatch protocol and register SMI callback functions.
446 //
447 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
448 ASSERT_EFI_ERROR (Status);
449 SwContext.SwSmiInputValue = (UINTN) -1;
450 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
451 ASSERT_EFI_ERROR (Status);
452 if (EFI_ERROR (Status)) {
453 return Status;
454 }
455 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
456
457 SwContext.SwSmiInputValue = (UINTN) -1;
458 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
459 ASSERT_EFI_ERROR (Status);
460 if (EFI_ERROR (Status)) {
461 return Status;
462 }
463 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
464
465 //
466 // Locate SmmVariableProtocol.
467 //
468 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
469 ASSERT_EFI_ERROR (Status);
470
471 //
472 // Set TPM2 ACPI table
473 //
474 Status = PublishTpm2 ();
475 ASSERT_EFI_ERROR (Status);
476
477
478 return EFI_SUCCESS;
479 }
480