2 It updates TPM2 items in ACPI table and registers SMI2 callback
3 functions for Tcg2 physical presence, ClearMemory, and sample
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.
10 PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.
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
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.
33 Return PTP interface type.
35 @param[in] Register Pointer to PTP register.
37 @return PTP interface type.
44 PTP_CRB_INTERFACE_IDENTIFIER InterfaceId
;
45 PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability
;
50 InterfaceId
.Uint32
= MmioRead32 ((UINTN
)&((PTP_CRB_REGISTERS
*)Register
)->InterfaceId
);
51 InterfaceCapability
.Uint32
= MmioRead32 ((UINTN
)&((PTP_FIFO_REGISTERS
*)Register
)->InterfaceCapability
);
53 if (InterfaceId
.Bits
.InterfaceType
== PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS
) {
54 return PtpInterfaceTis
;
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
;
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
;
71 // No Ptp interface available
73 return PtpInterfaceMax
;
76 EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate
= {
78 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE
,
79 sizeof (mTpm2AcpiTemplate
),
80 EFI_TPM2_ACPI_TABLE_REVISION
,
82 // Compiler initializes the remaining bytes to 0
83 // These fields should be filled in in production
88 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS
, // StartMethod
91 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
;
95 Software SMI callback for TPM physical presence which is called from ACPI method.
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.
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.
108 @retval EFI_SUCCESS The interrupt was handled successfully.
113 PhysicalPresenceCallback (
114 IN EFI_HANDLE DispatchHandle
,
115 IN CONST VOID
*Context
,
116 IN OUT VOID
*CommBuffer
,
117 IN OUT UINTN
*CommBufferSize
120 UINT32 MostRecentRequest
;
122 UINT32 OperationRequest
;
123 UINT32 RequestParameter
;
126 if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS
) {
127 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
131 mTcgNvs
->PhysicalPresence
.LastRequest
= MostRecentRequest
;
132 mTcgNvs
->PhysicalPresence
.Response
= Response
;
134 } else if ((mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS
)
135 || (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2
)) {
137 OperationRequest
= mTcgNvs
->PhysicalPresence
.Request
;
138 RequestParameter
= mTcgNvs
->PhysicalPresence
.RequestParameter
;
139 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
143 mTcgNvs
->PhysicalPresence
.Request
= OperationRequest
;
144 mTcgNvs
->PhysicalPresence
.RequestParameter
= RequestParameter
;
145 } else if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST
) {
146 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs
->PPRequestUserConfirm
);
154 Software SMI callback for MemoryClear which is called from ACPI method.
156 Caution: This function may receive untrusted input.
157 Variable and ACPINvs are external input, so this function will validate
158 its data structure to be valid value.
160 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
161 @param[in] Context Points to an optional handler context which was specified when the
162 handler was registered.
163 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
164 be conveyed from a non-SMM environment into an SMM environment.
165 @param[in, out] CommBufferSize The size of the CommBuffer.
167 @retval EFI_SUCCESS The interrupt was handled successfully.
172 MemoryClearCallback (
173 IN EFI_HANDLE DispatchHandle
,
174 IN CONST VOID
*Context
,
175 IN OUT VOID
*CommBuffer
,
176 IN OUT UINTN
*CommBufferSize
183 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_SUCCESS
;
184 if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE
) {
185 MorControl
= (UINT8
) mTcgNvs
->MemoryClear
.Request
;
186 } else if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_PTS_CLEAR_MOR_BIT
) {
187 DataSize
= sizeof (UINT8
);
188 Status
= mSmmVariable
->SmmGetVariable (
189 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
190 &gEfiMemoryOverwriteControlDataGuid
,
195 if (EFI_ERROR (Status
)) {
196 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
197 DEBUG ((EFI_D_ERROR
, "[TPM] Get MOR variable failure! Status = %r\n", Status
));
201 if (MOR_CLEAR_MEMORY_VALUE (MorControl
) == 0x0) {
204 MorControl
&= ~MOR_CLEAR_MEMORY_BIT_MASK
;
207 DataSize
= sizeof (UINT8
);
208 Status
= mSmmVariable
->SmmSetVariable (
209 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
210 &gEfiMemoryOverwriteControlDataGuid
,
211 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
215 if (EFI_ERROR (Status
)) {
216 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
217 DEBUG ((EFI_D_ERROR
, "[TPM] Set MOR variable failure! Status = %r\n", Status
));
224 Find the operation region in TCG ACPI table by given Name and Size,
225 and initialize it if the region is found.
227 @param[in, out] Table The TPM item in ACPI table.
228 @param[in] Name The name string to find in TPM table.
229 @param[in] Size The size of the region to find.
231 @return The allocated address for the found region.
236 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
242 AML_OP_REGION_32_8
*OpRegion
;
243 EFI_PHYSICAL_ADDRESS MemoryAddress
;
245 MemoryAddress
= SIZE_4GB
- 1;
248 // Patch some pointers for the ASL code before loading the SSDT.
250 for (OpRegion
= (AML_OP_REGION_32_8
*) (Table
+ 1);
251 OpRegion
<= (AML_OP_REGION_32_8
*) ((UINT8
*) Table
+ Table
->Length
);
252 OpRegion
= (AML_OP_REGION_32_8
*) ((UINT8
*) OpRegion
+ 1)) {
253 if ((OpRegion
->OpRegionOp
== AML_EXT_REGION_OP
) &&
254 (OpRegion
->NameString
== Name
) &&
255 (OpRegion
->DWordPrefix
== AML_DWORD_PREFIX
) &&
256 (OpRegion
->BytePrefix
== AML_BYTE_PREFIX
)) {
258 Status
= gBS
->AllocatePages(AllocateMaxAddress
, EfiACPIMemoryNVS
, EFI_SIZE_TO_PAGES (Size
), &MemoryAddress
);
259 ASSERT_EFI_ERROR (Status
);
260 ZeroMem ((VOID
*)(UINTN
)MemoryAddress
, Size
);
261 OpRegion
->RegionOffset
= (UINT32
) (UINTN
) MemoryAddress
;
262 OpRegion
->RegionLen
= (UINT8
) Size
;
267 return (VOID
*) (UINTN
) MemoryAddress
;
271 Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
274 @param[in, out] Table The TPM item in ACPI table.
275 @param[in] PPVer Version string of Physical Presence interface supported by platform.
277 @return The allocated address for the found region.
282 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
290 // Patch some pointers for the ASL code before loading the SSDT.
292 for (DataPtr
= (UINT8
*)(Table
+ 1);
293 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- PHYSICAL_PRESENCE_VERSION_SIZE
);
295 if (AsciiStrCmp((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_TAG
) == 0) {
296 Status
= AsciiStrCpyS((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_SIZE
, PPVer
);
297 DEBUG((EFI_D_INFO
, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status
));
302 return EFI_NOT_FOUND
;
306 Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000".
308 @param[in, out] Table The TPM2 SSDT ACPI table.
310 @return HID Update status.
315 EFI_ACPI_DESCRIPTION_HEADER
*Table
320 CHAR8 HID
[TPM_HID_ACPI_SIZE
];
321 UINT32 ManufacturerID
;
322 UINT32 FirmwareVersion1
;
323 UINT32 FirmwareVersion2
;
329 // Initialize HID with Default PNP string
331 ZeroMem(HID
, TPM_HID_ACPI_SIZE
);
332 CopyMem(HID
, TPM_HID_TAG
, TPM_HID_PNP_SIZE
);
335 // Get Manufacturer ID
337 Status
= Tpm2GetCapabilityManufactureID(&ManufacturerID
);
338 if (!EFI_ERROR(Status
)) {
339 DEBUG((EFI_D_INFO
, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID
));
341 // ManfacturerID defined in TCG Vendor ID Registry
342 // may tailed with 0x00 or 0x20
344 if ((ManufacturerID
>> 24) == 0x00 || ((ManufacturerID
>> 24) == 0x20)) {
346 // HID containing PNP ID "NNN####"
347 // NNN is uppercase letter for Vendor ID specified by manufacturer
349 CopyMem(HID
, &ManufacturerID
, 3);
352 // HID containing ACP ID "NNNN####"
353 // NNNN is uppercase letter for Vendor ID specified by manufacturer
355 CopyMem(HID
, &ManufacturerID
, 4);
359 DEBUG ((EFI_D_ERROR
, "Get TPM_PT_MANUFACTURER failed %x!\n", Status
));
364 Status
= Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1
, &FirmwareVersion2
);
365 if (!EFI_ERROR(Status
)) {
366 DEBUG((EFI_D_INFO
, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1
));
367 DEBUG((EFI_D_INFO
, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2
));
369 // #### is Firmware Version 1
372 AsciiSPrint(HID
+ 3, TPM_HID_PNP_SIZE
- 3, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
&& 0x0000FFFF));
374 AsciiSPrint(HID
+ 4, TPM_HID_ACPI_SIZE
- 4, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
&& 0x0000FFFF));
378 DEBUG ((EFI_D_ERROR
, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status
));
384 // Patch HID in ASL code before loading the SSDT.
386 for (DataPtr
= (UINT8
*)(Table
+ 1);
387 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- TPM_HID_PNP_SIZE
);
389 if (AsciiStrCmp((CHAR8
*)DataPtr
, TPM_HID_TAG
) == 0) {
391 CopyMem(DataPtr
, HID
, TPM_HID_PNP_SIZE
);
394 // NOOP will be patched to '\0'
396 CopyMem(DataPtr
, HID
, TPM_HID_ACPI_SIZE
);
398 DEBUG((EFI_D_INFO
, "TPM2 ACPI _HID updated to %a\n", HID
));
403 DEBUG((EFI_D_ERROR
, "TPM2 ACPI HID TAG for patch not found!\n"));
404 return EFI_NOT_FOUND
;
408 Initialize and publish TPM items in ACPI table.
410 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
411 @retval Others The TCG ACPI table is not published.
420 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
422 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
425 Status
= GetSectionFromFv (
432 ASSERT_EFI_ERROR (Status
);
435 // Update Table version before measuring it to PCR
437 Status
= UpdatePPVersion(Table
, (CHAR8
*)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer
));
438 ASSERT_EFI_ERROR (Status
);
441 // Update TPM2 HID before measuring it to PCR
443 Status
= UpdateHID(Table
);
444 if (EFI_ERROR(Status
)) {
449 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
451 TpmMeasureAndLogData(
454 EV_POSTCODE_INFO_ACPI_DATA
,
461 ASSERT (Table
->OemTableId
== SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
462 CopyMem (Table
->OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (Table
->OemId
) );
463 mTcgNvs
= AssignOpRegion (Table
, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16
) sizeof (TCG_NVS
));
464 ASSERT (mTcgNvs
!= NULL
);
467 // Publish the TPM ACPI table. Table is re-checksumed.
469 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
470 ASSERT_EFI_ERROR (Status
);
473 Status
= AcpiTable
->InstallAcpiTable (
479 ASSERT_EFI_ERROR (Status
);
485 Publish TPM2 ACPI table
487 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
488 @retval Others The TPM2 ACPI table is not published.
497 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
500 EFI_TPM2_ACPI_CONTROL_AREA
*ControlArea
;
501 PTP_INTERFACE_TYPE InterfaceType
;
504 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
506 TpmMeasureAndLogData(
509 EV_POSTCODE_INFO_ACPI_DATA
,
512 sizeof(mTpm2AcpiTemplate
)
515 InterfaceType
= GetPtpInterface ((VOID
*) (UINTN
) PcdGet64 (PcdTpmBaseAddress
));
516 switch (InterfaceType
) {
517 case PtpInterfaceCrb
:
518 mTpm2AcpiTemplate
.StartMethod
= EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE
;
519 mTpm2AcpiTemplate
.AddressOfControlArea
= PcdGet64 (PcdTpmBaseAddress
) + 0x40;
520 ControlArea
= (EFI_TPM2_ACPI_CONTROL_AREA
*)(UINTN
)mTpm2AcpiTemplate
.AddressOfControlArea
;
521 ControlArea
->CommandSize
= 0xF80;
522 ControlArea
->ResponseSize
= 0xF80;
523 ControlArea
->Command
= PcdGet64 (PcdTpmBaseAddress
) + 0x80;
524 ControlArea
->Response
= PcdGet64 (PcdTpmBaseAddress
) + 0x80;
526 case PtpInterfaceFifo
:
527 case PtpInterfaceTis
:
530 DEBUG((EFI_D_ERROR
, "TPM2 InterfaceType get error! %d\n", InterfaceType
));
534 CopyMem (mTpm2AcpiTemplate
.Header
.OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (mTpm2AcpiTemplate
.Header
.OemId
));
535 OemTableId
= PcdGet64 (PcdAcpiDefaultOemTableId
);
536 CopyMem (&mTpm2AcpiTemplate
.Header
.OemTableId
, &OemTableId
, sizeof (UINT64
));
537 mTpm2AcpiTemplate
.Header
.OemRevision
= PcdGet32 (PcdAcpiDefaultOemRevision
);
538 mTpm2AcpiTemplate
.Header
.CreatorId
= PcdGet32 (PcdAcpiDefaultCreatorId
);
539 mTpm2AcpiTemplate
.Header
.CreatorRevision
= PcdGet32 (PcdAcpiDefaultCreatorRevision
);
542 // Construct ACPI table
544 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
545 ASSERT_EFI_ERROR (Status
);
547 Status
= AcpiTable
->InstallAcpiTable (
550 sizeof(mTpm2AcpiTemplate
),
553 ASSERT_EFI_ERROR (Status
);
559 The driver's entry point.
561 It install callbacks for TPM physical presence and MemoryClear, and locate
562 SMM variable to be used in the callback function.
564 @param[in] ImageHandle The firmware allocated handle for the EFI image.
565 @param[in] SystemTable A pointer to the EFI System Table.
567 @retval EFI_SUCCESS The entry point is executed successfully.
568 @retval Others Some error occurs when executing this entry point.
574 IN EFI_HANDLE ImageHandle
,
575 IN EFI_SYSTEM_TABLE
*SystemTable
579 EFI_SMM_SW_DISPATCH2_PROTOCOL
*SwDispatch
;
580 EFI_SMM_SW_REGISTER_CONTEXT SwContext
;
583 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm20DtpmGuid
)){
584 DEBUG ((EFI_D_ERROR
, "No TPM2 DTPM instance required!\n"));
585 return EFI_UNSUPPORTED
;
588 Status
= PublishAcpiTable ();
589 ASSERT_EFI_ERROR (Status
);
592 // Get the Sw dispatch protocol and register SMI callback functions.
594 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid
, NULL
, (VOID
**)&SwDispatch
);
595 ASSERT_EFI_ERROR (Status
);
596 SwContext
.SwSmiInputValue
= (UINTN
) -1;
597 Status
= SwDispatch
->Register (SwDispatch
, PhysicalPresenceCallback
, &SwContext
, &SwHandle
);
598 ASSERT_EFI_ERROR (Status
);
599 if (EFI_ERROR (Status
)) {
602 mTcgNvs
->PhysicalPresence
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
604 SwContext
.SwSmiInputValue
= (UINTN
) -1;
605 Status
= SwDispatch
->Register (SwDispatch
, MemoryClearCallback
, &SwContext
, &SwHandle
);
606 ASSERT_EFI_ERROR (Status
);
607 if (EFI_ERROR (Status
)) {
610 mTcgNvs
->MemoryClear
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
613 // Locate SmmVariableProtocol.
615 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
616 ASSERT_EFI_ERROR (Status
);
619 // Set TPM2 ACPI table
621 Status
= PublishTpm2 ();
622 ASSERT_EFI_ERROR (Status
);