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
;
123 if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS
) {
124 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
128 mTcgNvs
->PhysicalPresence
.LastRequest
= MostRecentRequest
;
129 mTcgNvs
->PhysicalPresence
.Response
= Response
;
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
137 } else if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST
) {
138 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs
->PhysicalPresence
.Request
);
146 Software SMI callback for MemoryClear which is called from ACPI method.
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.
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.
159 @retval EFI_SUCCESS The interrupt was handled successfully.
164 MemoryClearCallback (
165 IN EFI_HANDLE DispatchHandle
,
166 IN CONST VOID
*Context
,
167 IN OUT VOID
*CommBuffer
,
168 IN OUT UINTN
*CommBufferSize
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
,
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
));
193 if (MOR_CLEAR_MEMORY_VALUE (MorControl
) == 0x0) {
196 MorControl
&= ~MOR_CLEAR_MEMORY_BIT_MASK
;
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
,
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
));
216 Find the operation region in TCG ACPI table by given Name and Size,
217 and initialize it if the region is found.
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.
223 @return The allocated address for the found region.
228 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
234 AML_OP_REGION_32_8
*OpRegion
;
235 EFI_PHYSICAL_ADDRESS MemoryAddress
;
237 MemoryAddress
= SIZE_4GB
- 1;
240 // Patch some pointers for the ASL code before loading the SSDT.
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
)) {
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
;
259 return (VOID
*) (UINTN
) MemoryAddress
;
263 Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
266 @param[in, out] Table The TPM item in ACPI table.
267 @param[in] PPVer Version string of Physical Presence interface supported by platform.
269 @return The allocated address for the found region.
274 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
282 // Patch some pointers for the ASL code before loading the SSDT.
284 for (DataPtr
= (UINT8
*)(Table
+ 1);
285 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- PHYSICAL_PRESENCE_VERSION_SIZE
);
287 if (AsciiStrCmp(DataPtr
, PHYSICAL_PRESENCE_VERSION_TAG
) == 0) {
288 Status
= AsciiStrCpyS(DataPtr
, PHYSICAL_PRESENCE_VERSION_SIZE
, PPVer
);
289 DEBUG((EFI_D_INFO
, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status
));
294 return EFI_NOT_FOUND
;
298 Initialize and publish TPM items in ACPI table.
300 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
301 @retval Others The TCG ACPI table is not published.
310 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
312 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
315 Status
= GetSectionFromFv (
322 ASSERT_EFI_ERROR (Status
);
325 // Update Table version before measuring it to PCR
327 Status
= UpdatePPVersion(Table
, (CHAR8
*)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer
));
328 ASSERT_EFI_ERROR (Status
);
331 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
333 TpmMeasureAndLogData(
336 EV_POSTCODE_INFO_ACPI_DATA
,
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
);
349 // Publish the TPM ACPI table. Table is re-checksumed.
351 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
352 ASSERT_EFI_ERROR (Status
);
355 Status
= AcpiTable
->InstallAcpiTable (
361 ASSERT_EFI_ERROR (Status
);
367 Publish TPM2 ACPI table
369 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
370 @retval Others The TPM2 ACPI table is not published.
379 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
382 EFI_TPM2_ACPI_CONTROL_AREA
*ControlArea
;
383 PTP_INTERFACE_TYPE InterfaceType
;
386 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
388 TpmMeasureAndLogData(
391 EV_POSTCODE_INFO_ACPI_DATA
,
394 sizeof(mTpm2AcpiTemplate
)
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;
408 case PtpInterfaceFifo
:
409 case PtpInterfaceTis
:
412 DEBUG((EFI_D_ERROR
, "TPM2 InterfaceType get error! %d\n", InterfaceType
));
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
);
424 // Construct ACPI table
426 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
427 ASSERT_EFI_ERROR (Status
);
429 Status
= AcpiTable
->InstallAcpiTable (
432 sizeof(mTpm2AcpiTemplate
),
435 ASSERT_EFI_ERROR (Status
);
441 The driver's entry point.
443 It install callbacks for TPM physical presence and MemoryClear, and locate
444 SMM variable to be used in the callback function.
446 @param[in] ImageHandle The firmware allocated handle for the EFI image.
447 @param[in] SystemTable A pointer to the EFI System Table.
449 @retval EFI_SUCCESS The entry point is executed successfully.
450 @retval Others Some error occurs when executing this entry point.
456 IN EFI_HANDLE ImageHandle
,
457 IN EFI_SYSTEM_TABLE
*SystemTable
461 EFI_SMM_SW_DISPATCH2_PROTOCOL
*SwDispatch
;
462 EFI_SMM_SW_REGISTER_CONTEXT SwContext
;
465 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm20DtpmGuid
)){
466 DEBUG ((EFI_D_ERROR
, "No TPM2 DTPM instance required!\n"));
467 return EFI_UNSUPPORTED
;
470 Status
= PublishAcpiTable ();
471 ASSERT_EFI_ERROR (Status
);
474 // Get the Sw dispatch protocol and register SMI callback functions.
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
)) {
484 mTcgNvs
->PhysicalPresence
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
486 SwContext
.SwSmiInputValue
= (UINTN
) -1;
487 Status
= SwDispatch
->Register (SwDispatch
, MemoryClearCallback
, &SwContext
, &SwHandle
);
488 ASSERT_EFI_ERROR (Status
);
489 if (EFI_ERROR (Status
)) {
492 mTcgNvs
->MemoryClear
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
495 // Locate SmmVariableProtocol.
497 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
498 ASSERT_EFI_ERROR (Status
);
501 // Set TPM2 ACPI table
503 Status
= PublishTpm2 ();
504 ASSERT_EFI_ERROR (Status
);