SecurityPkg: Tcg2Smm: Fix type casting issue
[mirror_edk2.git] / SecurityPkg / Tcg / Tcg2Smm / Tcg2Smm.c
1 /** @file
2 It updates TPM2 items in ACPI table and registers SMI2 callback
3 functions for Tcg2 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) 2015 - 2016, 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 "Tcg2Smm.h"
24
25 typedef enum {
26 PtpInterfaceTis,
27 PtpInterfaceFifo,
28 PtpInterfaceCrb,
29 PtpInterfaceMax,
30 } PTP_INTERFACE_TYPE;
31
32 /**
33 Return PTP interface type.
34
35 @param[in] Register Pointer to PTP register.
36
37 @return PTP interface type.
38 **/
39 PTP_INTERFACE_TYPE
40 GetPtpInterface (
41 IN VOID *Register
42 )
43 {
44 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;
45 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;
46
47 //
48 // Check interface id
49 //
50 InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);
51 InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);
52
53 if (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) {
54 return PtpInterfaceTis;
55 }
56
57 if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&
58 (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&
59 (InterfaceId.Bits.CapCRB != 0)) {
60 return PtpInterfaceCrb;
61 }
62
63 if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&
64 (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&
65 (InterfaceId.Bits.CapFIFO != 0) &&
66 (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {
67 return PtpInterfaceFifo;
68 }
69
70 //
71 // No Ptp interface available
72 //
73 return PtpInterfaceMax;
74 }
75
76 EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = {
77 {
78 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,
79 sizeof (mTpm2AcpiTemplate),
80 EFI_TPM2_ACPI_TABLE_REVISION,
81 //
82 // Compiler initializes the remaining bytes to 0
83 // These fields should be filled in in production
84 //
85 },
86 0, // Flags
87 0, // Control Area
88 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod
89 };
90
91 EFI_SMM_VARIABLE_PROTOCOL *mSmmVariable;
92 TCG_NVS *mTcgNvs;
93
94 /**
95 Software SMI callback for TPM physical presence which is called from ACPI method.
96
97 Caution: This function may receive untrusted input.
98 Variable and ACPINvs are external input, so this function will validate
99 its data structure to be valid value.
100
101 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
102 @param[in] Context Points to an optional handler context which was specified when the
103 handler was registered.
104 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
105 be conveyed from a non-SMM environment into an SMM environment.
106 @param[in, out] CommBufferSize The size of the CommBuffer.
107
108 @retval EFI_SUCCESS The interrupt was handled successfully.
109
110 **/
111 EFI_STATUS
112 EFIAPI
113 PhysicalPresenceCallback (
114 IN EFI_HANDLE DispatchHandle,
115 IN CONST VOID *Context,
116 IN OUT VOID *CommBuffer,
117 IN OUT UINTN *CommBufferSize
118 )
119 {
120 UINT32 MostRecentRequest;
121 UINT32 Response;
122
123 if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS) {
124 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
125 &MostRecentRequest,
126 &Response
127 );
128 mTcgNvs->PhysicalPresence.LastRequest = MostRecentRequest;
129 mTcgNvs->PhysicalPresence.Response = Response;
130 return EFI_SUCCESS;
131 } else if ((mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS)
132 || (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2)) {
133 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunction (
134 mTcgNvs->PhysicalPresence.Request,
135 mTcgNvs->PhysicalPresence.RequestParameter
136 );
137 } else if (mTcgNvs->PhysicalPresence.Parameter == TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST) {
138 mTcgNvs->PhysicalPresence.ReturnCode = Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs->PhysicalPresence.Request);
139 }
140
141 return EFI_SUCCESS;
142 }
143
144
145 /**
146 Software SMI callback for MemoryClear which is called from ACPI method.
147
148 Caution: This function may receive untrusted input.
149 Variable and ACPINvs are external input, so this function will validate
150 its data structure to be valid value.
151
152 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
153 @param[in] Context Points to an optional handler context which was specified when the
154 handler was registered.
155 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
156 be conveyed from a non-SMM environment into an SMM environment.
157 @param[in, out] CommBufferSize The size of the CommBuffer.
158
159 @retval EFI_SUCCESS The interrupt was handled successfully.
160
161 **/
162 EFI_STATUS
163 EFIAPI
164 MemoryClearCallback (
165 IN EFI_HANDLE DispatchHandle,
166 IN CONST VOID *Context,
167 IN OUT VOID *CommBuffer,
168 IN OUT UINTN *CommBufferSize
169 )
170 {
171 EFI_STATUS Status;
172 UINTN DataSize;
173 UINT8 MorControl;
174
175 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_SUCCESS;
176 if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE) {
177 MorControl = (UINT8) mTcgNvs->MemoryClear.Request;
178 } else if (mTcgNvs->MemoryClear.Parameter == ACPI_FUNCTION_PTS_CLEAR_MOR_BIT) {
179 DataSize = sizeof (UINT8);
180 Status = mSmmVariable->SmmGetVariable (
181 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
182 &gEfiMemoryOverwriteControlDataGuid,
183 NULL,
184 &DataSize,
185 &MorControl
186 );
187 if (EFI_ERROR (Status)) {
188 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
189 DEBUG ((EFI_D_ERROR, "[TPM] Get MOR variable failure! Status = %r\n", Status));
190 return EFI_SUCCESS;
191 }
192
193 if (MOR_CLEAR_MEMORY_VALUE (MorControl) == 0x0) {
194 return EFI_SUCCESS;
195 }
196 MorControl &= ~MOR_CLEAR_MEMORY_BIT_MASK;
197 }
198
199 DataSize = sizeof (UINT8);
200 Status = mSmmVariable->SmmSetVariable (
201 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME,
202 &gEfiMemoryOverwriteControlDataGuid,
203 EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
204 DataSize,
205 &MorControl
206 );
207 if (EFI_ERROR (Status)) {
208 mTcgNvs->MemoryClear.ReturnCode = MOR_REQUEST_GENERAL_FAILURE;
209 DEBUG ((EFI_D_ERROR, "[TPM] Set MOR variable failure! Status = %r\n", Status));
210 }
211
212 return EFI_SUCCESS;
213 }
214
215 /**
216 Find the operation region in TCG ACPI table by given Name and Size,
217 and initialize it if the region is found.
218
219 @param[in, out] Table The TPM item in ACPI table.
220 @param[in] Name The name string to find in TPM table.
221 @param[in] Size The size of the region to find.
222
223 @return The allocated address for the found region.
224
225 **/
226 VOID *
227 AssignOpRegion (
228 EFI_ACPI_DESCRIPTION_HEADER *Table,
229 UINT32 Name,
230 UINT16 Size
231 )
232 {
233 EFI_STATUS Status;
234 AML_OP_REGION_32_8 *OpRegion;
235 EFI_PHYSICAL_ADDRESS MemoryAddress;
236
237 MemoryAddress = SIZE_4GB - 1;
238
239 //
240 // Patch some pointers for the ASL code before loading the SSDT.
241 //
242 for (OpRegion = (AML_OP_REGION_32_8 *) (Table + 1);
243 OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);
244 OpRegion = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {
245 if ((OpRegion->OpRegionOp == AML_EXT_REGION_OP) &&
246 (OpRegion->NameString == Name) &&
247 (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&
248 (OpRegion->BytePrefix == AML_BYTE_PREFIX)) {
249
250 Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);
251 ASSERT_EFI_ERROR (Status);
252 ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);
253 OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;
254 OpRegion->RegionLen = (UINT8) Size;
255 break;
256 }
257 }
258
259 return (VOID *) (UINTN) MemoryAddress;
260 }
261
262 /**
263 Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
264 ACPI table is "$PV".
265
266 @param[in, out] Table The TPM item in ACPI table.
267 @param[in] PPVer Version string of Physical Presence interface supported by platform.
268
269 @return The allocated address for the found region.
270
271 **/
272 EFI_STATUS
273 UpdatePPVersion (
274 EFI_ACPI_DESCRIPTION_HEADER *Table,
275 CHAR8 *PPVer
276 )
277 {
278 EFI_STATUS Status;
279 UINT8 *DataPtr;
280
281 //
282 // Patch some pointers for the ASL code before loading the SSDT.
283 //
284 for (DataPtr = (UINT8 *)(Table + 1);
285 DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - PHYSICAL_PRESENCE_VERSION_SIZE);
286 DataPtr += 1) {
287 if (AsciiStrCmp((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_TAG) == 0) {
288 Status = AsciiStrCpyS((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_SIZE, PPVer);
289 DEBUG((EFI_D_INFO, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status));
290 return Status;
291 }
292 }
293
294 return EFI_NOT_FOUND;
295 }
296
297 /**
298 Initialize and publish TPM items in ACPI table.
299
300 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
301 @retval Others The TCG ACPI table is not published.
302
303 **/
304 EFI_STATUS
305 PublishAcpiTable (
306 VOID
307 )
308 {
309 EFI_STATUS Status;
310 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
311 UINTN TableKey;
312 EFI_ACPI_DESCRIPTION_HEADER *Table;
313 UINTN TableSize;
314
315 Status = GetSectionFromFv (
316 &gEfiCallerIdGuid,
317 EFI_SECTION_RAW,
318 0,
319 (VOID **) &Table,
320 &TableSize
321 );
322 ASSERT_EFI_ERROR (Status);
323
324 //
325 // Update Table version before measuring it to PCR
326 //
327 Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer));
328 ASSERT_EFI_ERROR (Status);
329
330 //
331 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
332 //
333 TpmMeasureAndLogData(
334 0,
335 EV_POST_CODE,
336 EV_POSTCODE_INFO_ACPI_DATA,
337 ACPI_DATA_LEN,
338 Table,
339 TableSize
340 );
341
342
343 ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
344 CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );
345 mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));
346 ASSERT (mTcgNvs != NULL);
347
348 //
349 // Publish the TPM ACPI table. Table is re-checksumed.
350 //
351 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
352 ASSERT_EFI_ERROR (Status);
353
354 TableKey = 0;
355 Status = AcpiTable->InstallAcpiTable (
356 AcpiTable,
357 Table,
358 TableSize,
359 &TableKey
360 );
361 ASSERT_EFI_ERROR (Status);
362
363 return Status;
364 }
365
366 /**
367 Publish TPM2 ACPI table
368
369 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
370 @retval Others The TPM2 ACPI table is not published.
371
372 **/
373 EFI_STATUS
374 PublishTpm2 (
375 VOID
376 )
377 {
378 EFI_STATUS Status;
379 EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
380 UINTN TableKey;
381 UINT64 OemTableId;
382 EFI_TPM2_ACPI_CONTROL_AREA *ControlArea;
383 PTP_INTERFACE_TYPE InterfaceType;
384
385 //
386 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
387 //
388 TpmMeasureAndLogData(
389 0,
390 EV_POST_CODE,
391 EV_POSTCODE_INFO_ACPI_DATA,
392 ACPI_DATA_LEN,
393 &mTpm2AcpiTemplate,
394 sizeof(mTpm2AcpiTemplate)
395 );
396
397 InterfaceType = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));
398 switch (InterfaceType) {
399 case PtpInterfaceCrb:
400 mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE;
401 mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40;
402 ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea;
403 ControlArea->CommandSize = 0xF80;
404 ControlArea->ResponseSize = 0xF80;
405 ControlArea->Command = PcdGet64 (PcdTpmBaseAddress) + 0x80;
406 ControlArea->Response = PcdGet64 (PcdTpmBaseAddress) + 0x80;
407 break;
408 case PtpInterfaceFifo:
409 case PtpInterfaceTis:
410 break;
411 default:
412 DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType));
413 break;
414 }
415
416 CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));
417 OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);
418 CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));
419 mTpm2AcpiTemplate.Header.OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
420 mTpm2AcpiTemplate.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
421 mTpm2AcpiTemplate.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
422
423 //
424 // Construct ACPI table
425 //
426 Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
427 ASSERT_EFI_ERROR (Status);
428
429 Status = AcpiTable->InstallAcpiTable (
430 AcpiTable,
431 &mTpm2AcpiTemplate,
432 sizeof(mTpm2AcpiTemplate),
433 &TableKey
434 );
435 ASSERT_EFI_ERROR (Status);
436
437 return Status;
438 }
439
440 /**
441 The driver's entry point.
442
443 It install callbacks for TPM physical presence and MemoryClear, and locate
444 SMM variable to be used in the callback function.
445
446 @param[in] ImageHandle The firmware allocated handle for the EFI image.
447 @param[in] SystemTable A pointer to the EFI System Table.
448
449 @retval EFI_SUCCESS The entry point is executed successfully.
450 @retval Others Some error occurs when executing this entry point.
451
452 **/
453 EFI_STATUS
454 EFIAPI
455 InitializeTcgSmm (
456 IN EFI_HANDLE ImageHandle,
457 IN EFI_SYSTEM_TABLE *SystemTable
458 )
459 {
460 EFI_STATUS Status;
461 EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
462 EFI_SMM_SW_REGISTER_CONTEXT SwContext;
463 EFI_HANDLE SwHandle;
464
465 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){
466 DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));
467 return EFI_UNSUPPORTED;
468 }
469
470 Status = PublishAcpiTable ();
471 ASSERT_EFI_ERROR (Status);
472
473 //
474 // Get the Sw dispatch protocol and register SMI callback functions.
475 //
476 Status = gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);
477 ASSERT_EFI_ERROR (Status);
478 SwContext.SwSmiInputValue = (UINTN) -1;
479 Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);
480 ASSERT_EFI_ERROR (Status);
481 if (EFI_ERROR (Status)) {
482 return Status;
483 }
484 mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
485
486 SwContext.SwSmiInputValue = (UINTN) -1;
487 Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);
488 ASSERT_EFI_ERROR (Status);
489 if (EFI_ERROR (Status)) {
490 return Status;
491 }
492 mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;
493
494 //
495 // Locate SmmVariableProtocol.
496 //
497 Status = gSmst->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);
498 ASSERT_EFI_ERROR (Status);
499
500 //
501 // Set TPM2 ACPI table
502 //
503 Status = PublishTpm2 ();
504 ASSERT_EFI_ERROR (Status);
505
506
507 return EFI_SUCCESS;
508 }
509