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 - 2018, Intel Corporation. All rights reserved.<BR>
13 SPDX-License-Identifier: BSD-2-Clause-Patent
22 EFI_ACPI_DESCRIPTION_HEADER Header
;
23 // Flags field is replaced in version 4 and above
24 // BIT0~15: PlatformClass This field is only valid for version 4 and above
27 UINT64 AddressOfControlArea
;
29 UINT8 PlatformSpecificParameters
[12]; // size up to 12
30 UINT32 Laml
; // Optional
31 UINT64 Lasa
; // Optional
32 } EFI_TPM2_ACPI_TABLE_V4
;
36 EFI_TPM2_ACPI_TABLE_V4 mTpm2AcpiTemplate
= {
38 EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE
,
39 sizeof (mTpm2AcpiTemplate
),
40 EFI_TPM2_ACPI_TABLE_REVISION
,
42 // Compiler initializes the remaining bytes to 0
43 // These fields should be filled in in production
46 0, // BIT0~15: PlatformClass
49 EFI_TPM2_ACPI_TABLE_START_METHOD_TIS
, // StartMethod
52 EFI_SMM_VARIABLE_PROTOCOL
*mSmmVariable
;
56 Software SMI callback for TPM physical presence which is called from ACPI method.
58 Caution: This function may receive untrusted input.
59 Variable and ACPINvs are external input, so this function will validate
60 its data structure to be valid value.
62 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
63 @param[in] Context Points to an optional handler context which was specified when the
64 handler was registered.
65 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
66 be conveyed from a non-SMM environment into an SMM environment.
67 @param[in, out] CommBufferSize The size of the CommBuffer.
69 @retval EFI_SUCCESS The interrupt was handled successfully.
74 PhysicalPresenceCallback (
75 IN EFI_HANDLE DispatchHandle
,
76 IN CONST VOID
*Context
,
77 IN OUT VOID
*CommBuffer
,
78 IN OUT UINTN
*CommBufferSize
81 UINT32 MostRecentRequest
;
83 UINT32 OperationRequest
;
84 UINT32 RequestParameter
;
87 if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_RETURN_REQUEST_RESPONSE_TO_OS
) {
88 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibReturnOperationResponseToOsFunction (
92 mTcgNvs
->PhysicalPresence
.LastRequest
= MostRecentRequest
;
93 mTcgNvs
->PhysicalPresence
.Response
= Response
;
95 } else if ((mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS
)
96 || (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_SUBMIT_REQUEST_TO_BIOS_2
)) {
98 OperationRequest
= mTcgNvs
->PhysicalPresence
.Request
;
99 RequestParameter
= mTcgNvs
->PhysicalPresence
.RequestParameter
;
100 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibSubmitRequestToPreOSFunctionEx (
104 mTcgNvs
->PhysicalPresence
.Request
= OperationRequest
;
105 mTcgNvs
->PhysicalPresence
.RequestParameter
= RequestParameter
;
106 } else if (mTcgNvs
->PhysicalPresence
.Parameter
== TCG_ACPI_FUNCTION_GET_USER_CONFIRMATION_STATUS_FOR_REQUEST
) {
107 mTcgNvs
->PhysicalPresence
.ReturnCode
= Tcg2PhysicalPresenceLibGetUserConfirmationStatusFunction (mTcgNvs
->PPRequestUserConfirm
);
115 Software SMI callback for MemoryClear which is called from ACPI method.
117 Caution: This function may receive untrusted input.
118 Variable and ACPINvs are external input, so this function will validate
119 its data structure to be valid value.
121 @param[in] DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
122 @param[in] Context Points to an optional handler context which was specified when the
123 handler was registered.
124 @param[in, out] CommBuffer A pointer to a collection of data in memory that will
125 be conveyed from a non-SMM environment into an SMM environment.
126 @param[in, out] CommBufferSize The size of the CommBuffer.
128 @retval EFI_SUCCESS The interrupt was handled successfully.
133 MemoryClearCallback (
134 IN EFI_HANDLE DispatchHandle
,
135 IN CONST VOID
*Context
,
136 IN OUT VOID
*CommBuffer
,
137 IN OUT UINTN
*CommBufferSize
144 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_SUCCESS
;
145 if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_DSM_MEMORY_CLEAR_INTERFACE
) {
146 MorControl
= (UINT8
) mTcgNvs
->MemoryClear
.Request
;
147 } else if (mTcgNvs
->MemoryClear
.Parameter
== ACPI_FUNCTION_PTS_CLEAR_MOR_BIT
) {
148 DataSize
= sizeof (UINT8
);
149 Status
= mSmmVariable
->SmmGetVariable (
150 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
151 &gEfiMemoryOverwriteControlDataGuid
,
156 if (EFI_ERROR (Status
)) {
157 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
158 DEBUG ((EFI_D_ERROR
, "[TPM] Get MOR variable failure! Status = %r\n", Status
));
162 if (MOR_CLEAR_MEMORY_VALUE (MorControl
) == 0x0) {
165 MorControl
&= ~MOR_CLEAR_MEMORY_BIT_MASK
;
167 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
168 DEBUG ((EFI_D_ERROR
, "[TPM] MOR Parameter error! Parameter = %x\n", mTcgNvs
->MemoryClear
.Parameter
));
172 DataSize
= sizeof (UINT8
);
173 Status
= mSmmVariable
->SmmSetVariable (
174 MEMORY_OVERWRITE_REQUEST_VARIABLE_NAME
,
175 &gEfiMemoryOverwriteControlDataGuid
,
176 EFI_VARIABLE_NON_VOLATILE
| EFI_VARIABLE_BOOTSERVICE_ACCESS
| EFI_VARIABLE_RUNTIME_ACCESS
,
180 if (EFI_ERROR (Status
)) {
181 mTcgNvs
->MemoryClear
.ReturnCode
= MOR_REQUEST_GENERAL_FAILURE
;
182 DEBUG ((EFI_D_ERROR
, "[TPM] Set MOR variable failure! Status = %r\n", Status
));
189 Find the operation region in TCG ACPI table by given Name and Size,
190 and initialize it if the region is found.
192 @param[in, out] Table The TPM item in ACPI table.
193 @param[in] Name The name string to find in TPM table.
194 @param[in] Size The size of the region to find.
196 @return The allocated address for the found region.
201 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
207 AML_OP_REGION_32_8
*OpRegion
;
208 EFI_PHYSICAL_ADDRESS MemoryAddress
;
210 MemoryAddress
= SIZE_4GB
- 1;
213 // Patch some pointers for the ASL code before loading the SSDT.
215 for (OpRegion
= (AML_OP_REGION_32_8
*) (Table
+ 1);
216 OpRegion
<= (AML_OP_REGION_32_8
*) ((UINT8
*) Table
+ Table
->Length
);
217 OpRegion
= (AML_OP_REGION_32_8
*) ((UINT8
*) OpRegion
+ 1)) {
218 if ((OpRegion
->OpRegionOp
== AML_EXT_REGION_OP
) &&
219 (OpRegion
->NameString
== Name
) &&
220 (OpRegion
->DWordPrefix
== AML_DWORD_PREFIX
) &&
221 (OpRegion
->BytePrefix
== AML_BYTE_PREFIX
)) {
223 Status
= gBS
->AllocatePages(AllocateMaxAddress
, EfiACPIMemoryNVS
, EFI_SIZE_TO_PAGES (Size
), &MemoryAddress
);
224 ASSERT_EFI_ERROR (Status
);
225 ZeroMem ((VOID
*)(UINTN
)MemoryAddress
, Size
);
226 OpRegion
->RegionOffset
= (UINT32
) (UINTN
) MemoryAddress
;
227 OpRegion
->RegionLen
= (UINT8
) Size
;
232 return (VOID
*) (UINTN
) MemoryAddress
;
236 Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM
239 @param[in, out] Table The TPM item in ACPI table.
240 @param[in] PPVer Version string of Physical Presence interface supported by platform.
242 @return The allocated address for the found region.
247 EFI_ACPI_DESCRIPTION_HEADER
*Table
,
255 // Patch some pointers for the ASL code before loading the SSDT.
257 for (DataPtr
= (UINT8
*)(Table
+ 1);
258 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- PHYSICAL_PRESENCE_VERSION_SIZE
);
260 if (AsciiStrCmp((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_TAG
) == 0) {
261 Status
= AsciiStrCpyS((CHAR8
*)DataPtr
, PHYSICAL_PRESENCE_VERSION_SIZE
, PPVer
);
262 DEBUG((EFI_D_INFO
, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status
));
267 return EFI_NOT_FOUND
;
271 Patch interrupt resources returned by TPM _PRS. ResourceTemplate to patch is determined by input
272 interrupt buffer size. BufferSize, PkgLength and interrupt descriptor in ByteList need to be patched
274 @param[in, out] Table The TPM item in ACPI table.
275 @param[in] IrqBuffer Input new IRQ buffer.
276 @param[in] IrqBuffserSize Input new IRQ buffer size.
277 @param[out] IsShortFormPkgLength If _PRS returns Short length Package(ACPI spec 20.2.4).
279 @return patch status.
283 UpdatePossibleResource (
284 IN OUT EFI_ACPI_DESCRIPTION_HEADER
*Table
,
285 IN UINT32
*IrqBuffer
,
286 IN UINT32 IrqBuffserSize
,
287 OUT BOOLEAN
*IsShortFormPkgLength
293 UINT32 OrignalPkgLength
;
296 OrignalPkgLength
= 0;
301 // 6.4.3 Extend Interrupt Descriptor.
302 // 19.3.3 ASL Resource Template
303 // 20 AML specification
304 // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag
306 // AML data is organized by following rule.
307 // Code need to patch BufferSize and PkgLength and interrupt descriptor in ByteList
309 // ============= Buffer ====================
310 // DefBuffer := BufferOp PkgLength BufferSize ByteList
313 // ==============PkgLength==================
314 // PkgLength := PkgLeadByte |
315 // <PkgLeadByte ByteData> |
316 // <PkgLeadByte ByteData ByteData> |
317 // <PkgLeadByte ByteData ByteData ByteData>
319 // PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>
320 // <bit 5-4: Only used if PkgLength <= 63 >
321 // <bit 3-0: Least significant package length nybble>
323 //==============BufferSize==================
324 // BufferSize := Integer
325 // Integer := ByteConst|WordConst|DwordConst....
327 // ByteConst := BytePrefix ByteData
329 //==============ByteList===================
330 // ByteList := ByteData ByteList
332 //=========================================
335 // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching
337 for (DataPtr
= (UINT8
*)(Table
+ 1);
338 DataPtr
< (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
));
340 if (CompareMem(DataPtr
, TPM_PRS_RESS
, TPM_PRS_RES_NAME_SIZE
) == 0) {
342 // Jump over object name & BufferOp
344 DataPtr
+= TPM_PRS_RES_NAME_SIZE
+ 1;
346 if ((*DataPtr
& (BIT7
|BIT6
)) == 0) {
347 OrignalPkgLength
= (UINT32
)*DataPtr
;
348 DataEndPtr
= DataPtr
+ OrignalPkgLength
;
351 // Jump over PkgLength = PkgLeadByte only
356 // Jump over BufferSize
358 if (*(DataPtr
+ 1) == AML_BYTE_PREFIX
) {
360 } else if (*(DataPtr
+ 1) == AML_WORD_PREFIX
) {
362 } else if (*(DataPtr
+ 1) == AML_DWORD_PREFIX
) {
366 return EFI_UNSUPPORTED
;
370 return EFI_UNSUPPORTED
;
374 // Include Memory32Fixed Descriptor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
376 NewPkgLength
+= 19 + IrqBuffserSize
;
377 if (NewPkgLength
> 63) {
381 if (NewPkgLength
> OrignalPkgLength
) {
383 return EFI_INVALID_PARAMETER
;
387 // 1.1 Patch PkgLength
389 *DataPtr
= (UINT8
)NewPkgLength
;
392 // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descriptor + Interrupt Descriptor + End Tag).
393 // It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit.
395 *(DataPtr
+ 2) = (UINT8
)(IrqBuffserSize
+ 19);
398 // Notify _PRS to report short formed ResourceTemplate
400 *IsShortFormPkgLength
= TRUE
;
407 // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching
409 if (NewPkgLength
> 63) {
411 OrignalPkgLength
= 0;
412 for (DataPtr
= (UINT8
*)(Table
+ 1);
413 DataPtr
< (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
));
415 if (CompareMem(DataPtr
, TPM_PRS_RESL
, TPM_PRS_RES_NAME_SIZE
) == 0) {
417 // Jump over object name & BufferOp
419 DataPtr
+= TPM_PRS_RES_NAME_SIZE
+ 1;
421 if ((*DataPtr
& (BIT7
|BIT6
)) != 0) {
422 OrignalPkgLength
= (UINT32
)(*(DataPtr
+ 1) << 4) + (*DataPtr
& 0x0F);
423 DataEndPtr
= DataPtr
+ OrignalPkgLength
;
425 // Jump over PkgLength = PkgLeadByte + ByteData length
427 NewPkgLength
+= 1 + ((*DataPtr
& (BIT7
|BIT6
)) >> 6);
430 // Jump over BufferSize
432 if (*(DataPtr
+ NewPkgLength
) == AML_BYTE_PREFIX
) {
434 } else if (*(DataPtr
+ NewPkgLength
) == AML_WORD_PREFIX
) {
436 } else if (*(DataPtr
+ NewPkgLength
) == AML_DWORD_PREFIX
) {
440 return EFI_UNSUPPORTED
;
444 return EFI_UNSUPPORTED
;
448 // Include Memory32Fixed Descriptor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)
450 NewPkgLength
+= 19 + IrqBuffserSize
;
452 if (NewPkgLength
> OrignalPkgLength
) {
454 return EFI_INVALID_PARAMETER
;
458 // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData
460 *DataPtr
= (UINT8
)((*DataPtr
) & 0xF0) | (NewPkgLength
& 0x0F);
461 *(DataPtr
+ 1) = (UINT8
)((NewPkgLength
& 0xFF0) >> 4);
464 // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descriptor + Interrupt Descriptor + End Tag).
465 // It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit.
467 *(DataPtr
+ 2 + ((*DataPtr
& (BIT7
|BIT6
)) >> 6)) = (UINT8
)(IrqBuffserSize
+ 19);
470 // Notify _PRS to report long formed ResourceTemplate
472 *IsShortFormPkgLength
= FALSE
;
478 if (DataPtr
>= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- (TPM_PRS_RES_NAME_SIZE
+ TPM_POS_RES_TEMPLATE_MIN_SIZE
))) {
479 return EFI_NOT_FOUND
;
483 // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor.
484 // 5 bytes for interrupt descriptor header, 2 bytes for End Tag
486 DataPtr
+= NewPkgLength
- (5 + IrqBuffserSize
+ 2);
488 // 3.1 Patch Length bit[7:0] of Interrupt descriptor patch interrupt descriptor
490 *(DataPtr
+ 1) = (UINT8
)(2 + IrqBuffserSize
);
492 // 3.2 Patch Interrupt Table Length
494 *(DataPtr
+ 4) = (UINT8
)(IrqBuffserSize
/ sizeof(UINT32
));
496 // 3.3 Copy patched InterruptNumBuffer
498 CopyMem(DataPtr
+ 5, IrqBuffer
, IrqBuffserSize
);
501 // 4. Jump over Interrupt descriptor and Patch END Tag, set Checksum field to 0
503 DataPtr
+= 5 + IrqBuffserSize
;
504 *DataPtr
= ACPI_END_TAG_DESCRIPTOR
;
508 // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP
511 if (DataPtr
< DataEndPtr
) {
512 SetMem(DataPtr
, (UINTN
)DataEndPtr
- (UINTN
)DataPtr
, AML_NOOP_OP
);
519 Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000".
521 @param[in, out] Table The TPM2 SSDT ACPI table.
523 @return HID Update status.
528 EFI_ACPI_DESCRIPTION_HEADER
*Table
533 CHAR8 Hid
[TPM_HID_ACPI_SIZE
];
534 UINT32 ManufacturerID
;
535 UINT32 FirmwareVersion1
;
536 UINT32 FirmwareVersion2
;
542 // Initialize HID with Default PNP string
544 ZeroMem(Hid
, TPM_HID_ACPI_SIZE
);
547 // Get Manufacturer ID
549 Status
= Tpm2GetCapabilityManufactureID(&ManufacturerID
);
550 if (!EFI_ERROR(Status
)) {
551 DEBUG((EFI_D_INFO
, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID
));
553 // ManufacturerID defined in TCG Vendor ID Registry
554 // may tailed with 0x00 or 0x20
556 if ((ManufacturerID
>> 24) == 0x00 || ((ManufacturerID
>> 24) == 0x20)) {
558 // HID containing PNP ID "NNN####"
559 // NNN is uppercase letter for Vendor ID specified by manufacturer
561 CopyMem(Hid
, &ManufacturerID
, 3);
564 // HID containing ACP ID "NNNN####"
565 // NNNN is uppercase letter for Vendor ID specified by manufacturer
567 CopyMem(Hid
, &ManufacturerID
, 4);
571 DEBUG ((EFI_D_ERROR
, "Get TPM_PT_MANUFACTURER failed %x!\n", Status
));
576 Status
= Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1
, &FirmwareVersion2
);
577 if (!EFI_ERROR(Status
)) {
578 DEBUG((EFI_D_INFO
, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1
));
579 DEBUG((EFI_D_INFO
, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2
));
581 // #### is Firmware Version 1
584 AsciiSPrint(Hid
+ 3, TPM_HID_PNP_SIZE
- 3, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
& 0x0000FFFF));
586 AsciiSPrint(Hid
+ 4, TPM_HID_ACPI_SIZE
- 4, "%02d%02d", ((FirmwareVersion1
& 0xFFFF0000) >> 16), (FirmwareVersion1
& 0x0000FFFF));
590 DEBUG ((EFI_D_ERROR
, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status
));
596 // Patch HID in ASL code before loading the SSDT.
598 for (DataPtr
= (UINT8
*)(Table
+ 1);
599 DataPtr
<= (UINT8
*) ((UINT8
*) Table
+ Table
->Length
- TPM_HID_PNP_SIZE
);
601 if (AsciiStrCmp((CHAR8
*)DataPtr
, TPM_HID_TAG
) == 0) {
603 CopyMem(DataPtr
, Hid
, TPM_HID_PNP_SIZE
);
605 // if HID is PNP ID, patch the last byte in HID TAG to Noop
607 *(DataPtr
+ TPM_HID_PNP_SIZE
) = AML_NOOP_OP
;
610 CopyMem(DataPtr
, Hid
, TPM_HID_ACPI_SIZE
);
612 DEBUG((DEBUG_INFO
, "TPM2 ACPI _HID is patched to %a\n", DataPtr
));
618 DEBUG((EFI_D_ERROR
, "TPM2 ACPI HID TAG for patch not found!\n"));
619 return EFI_NOT_FOUND
;
623 Initialize and publish TPM items in ACPI table.
625 @retval EFI_SUCCESS The TCG ACPI table is published successfully.
626 @retval Others The TCG ACPI table is not published.
635 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
637 EFI_ACPI_DESCRIPTION_HEADER
*Table
;
639 UINT32
*PossibleIrqNumBuf
;
640 UINT32 PossibleIrqNumBufSize
;
641 BOOLEAN IsShortFormPkgLength
;
643 IsShortFormPkgLength
= FALSE
;
645 Status
= GetSectionFromFv (
652 ASSERT_EFI_ERROR (Status
);
655 // Update Table version before measuring it to PCR
657 Status
= UpdatePPVersion(Table
, (CHAR8
*)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer
));
658 ASSERT_EFI_ERROR (Status
);
662 "Current physical presence interface version - %a\n",
663 (CHAR8
*) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer
)
667 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA.
668 // The measurement has to be done before UpdateHID since TPM2 ACPI HID
669 // imply TPM Firmware Version. Otherwise, the PCR record would be
670 // different after TPM FW update.
672 TpmMeasureAndLogData(
675 EV_POSTCODE_INFO_ACPI_DATA
,
682 // Update TPM2 HID after measuring it to PCR
684 Status
= UpdateHID(Table
);
685 if (EFI_ERROR(Status
)) {
689 if (PcdGet32(PcdTpm2CurrentIrqNum
) != 0) {
691 // Patch _PRS interrupt resource only when TPM interrupt is supported
693 PossibleIrqNumBuf
= (UINT32
*)PcdGetPtr(PcdTpm2PossibleIrqNumBuf
);
694 PossibleIrqNumBufSize
= (UINT32
)PcdGetSize(PcdTpm2PossibleIrqNumBuf
);
696 if (PossibleIrqNumBufSize
<= MAX_PRS_INT_BUF_SIZE
&& (PossibleIrqNumBufSize
% sizeof(UINT32
)) == 0) {
697 Status
= UpdatePossibleResource(Table
, PossibleIrqNumBuf
, PossibleIrqNumBufSize
, &IsShortFormPkgLength
);
700 "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",
706 "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",
707 PossibleIrqNumBufSize
712 ASSERT (Table
->OemTableId
== SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));
713 CopyMem (Table
->OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (Table
->OemId
) );
714 mTcgNvs
= AssignOpRegion (Table
, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16
) sizeof (TCG_NVS
));
715 ASSERT (mTcgNvs
!= NULL
);
716 mTcgNvs
->TpmIrqNum
= PcdGet32(PcdTpm2CurrentIrqNum
);
717 mTcgNvs
->IsShortFormPkgLength
= IsShortFormPkgLength
;
720 // Publish the TPM ACPI table. Table is re-checksummed.
722 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
723 ASSERT_EFI_ERROR (Status
);
726 Status
= AcpiTable
->InstallAcpiTable (
732 ASSERT_EFI_ERROR (Status
);
738 Publish TPM2 ACPI table
740 @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.
741 @retval Others The TPM2 ACPI table is not published.
750 EFI_ACPI_TABLE_PROTOCOL
*AcpiTable
;
753 EFI_TPM2_ACPI_CONTROL_AREA
*ControlArea
;
754 TPM2_PTP_INTERFACE_TYPE InterfaceType
;
756 mTpm2AcpiTemplate
.Header
.Revision
= PcdGet8(PcdTpm2AcpiTableRev
);
757 DEBUG((DEBUG_INFO
, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate
.Header
.Revision
));
760 // PlatformClass is only valid for version 4 and above
761 // BIT0~15: PlatformClass
762 // BIT16~31: Reserved
764 if (mTpm2AcpiTemplate
.Header
.Revision
>= EFI_TPM2_ACPI_TABLE_REVISION_4
) {
765 mTpm2AcpiTemplate
.Flags
= (mTpm2AcpiTemplate
.Flags
& 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass
);
766 DEBUG((DEBUG_INFO
, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate
.Flags
& 0x0000FFFF)));
769 mTpm2AcpiTemplate
.Laml
= PcdGet32(PcdTpm2AcpiTableLaml
);
770 mTpm2AcpiTemplate
.Lasa
= PcdGet64(PcdTpm2AcpiTableLasa
);
771 if ((mTpm2AcpiTemplate
.Header
.Revision
< EFI_TPM2_ACPI_TABLE_REVISION_4
) ||
772 (mTpm2AcpiTemplate
.Laml
== 0) || (mTpm2AcpiTemplate
.Lasa
== 0)) {
774 // If version is smaller than 4 or Laml/Lasa is not valid, rollback to original Length.
776 mTpm2AcpiTemplate
.Header
.Length
= sizeof(EFI_TPM2_ACPI_TABLE
);
780 // Measure to PCR[0] with event EV_POST_CODE ACPI DATA
782 TpmMeasureAndLogData(
785 EV_POSTCODE_INFO_ACPI_DATA
,
788 mTpm2AcpiTemplate
.Header
.Length
791 InterfaceType
= PcdGet8(PcdActiveTpmInterfaceType
);
792 switch (InterfaceType
) {
793 case Tpm2PtpInterfaceCrb
:
794 mTpm2AcpiTemplate
.StartMethod
= EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE
;
795 mTpm2AcpiTemplate
.AddressOfControlArea
= PcdGet64 (PcdTpmBaseAddress
) + 0x40;
796 ControlArea
= (EFI_TPM2_ACPI_CONTROL_AREA
*)(UINTN
)mTpm2AcpiTemplate
.AddressOfControlArea
;
797 ControlArea
->CommandSize
= 0xF80;
798 ControlArea
->ResponseSize
= 0xF80;
799 ControlArea
->Command
= PcdGet64 (PcdTpmBaseAddress
) + 0x80;
800 ControlArea
->Response
= PcdGet64 (PcdTpmBaseAddress
) + 0x80;
802 case Tpm2PtpInterfaceFifo
:
803 case Tpm2PtpInterfaceTis
:
806 DEBUG((EFI_D_ERROR
, "TPM2 InterfaceType get error! %d\n", InterfaceType
));
810 CopyMem (mTpm2AcpiTemplate
.Header
.OemId
, PcdGetPtr (PcdAcpiDefaultOemId
), sizeof (mTpm2AcpiTemplate
.Header
.OemId
));
811 OemTableId
= PcdGet64 (PcdAcpiDefaultOemTableId
);
812 CopyMem (&mTpm2AcpiTemplate
.Header
.OemTableId
, &OemTableId
, sizeof (UINT64
));
813 mTpm2AcpiTemplate
.Header
.OemRevision
= PcdGet32 (PcdAcpiDefaultOemRevision
);
814 mTpm2AcpiTemplate
.Header
.CreatorId
= PcdGet32 (PcdAcpiDefaultCreatorId
);
815 mTpm2AcpiTemplate
.Header
.CreatorRevision
= PcdGet32 (PcdAcpiDefaultCreatorRevision
);
818 // Construct ACPI table
820 Status
= gBS
->LocateProtocol (&gEfiAcpiTableProtocolGuid
, NULL
, (VOID
**) &AcpiTable
);
821 ASSERT_EFI_ERROR (Status
);
823 Status
= AcpiTable
->InstallAcpiTable (
826 mTpm2AcpiTemplate
.Header
.Length
,
829 ASSERT_EFI_ERROR (Status
);
835 The driver's entry point.
837 It install callbacks for TPM physical presence and MemoryClear, and locate
838 SMM variable to be used in the callback function.
840 @param[in] ImageHandle The firmware allocated handle for the EFI image.
841 @param[in] SystemTable A pointer to the EFI System Table.
843 @retval EFI_SUCCESS The entry point is executed successfully.
844 @retval Others Some error occurs when executing this entry point.
850 IN EFI_HANDLE ImageHandle
,
851 IN EFI_SYSTEM_TABLE
*SystemTable
855 EFI_SMM_SW_DISPATCH2_PROTOCOL
*SwDispatch
;
856 EFI_SMM_SW_REGISTER_CONTEXT SwContext
;
859 if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid
), &gEfiTpmDeviceInstanceTpm20DtpmGuid
)){
860 DEBUG ((EFI_D_ERROR
, "No TPM2 DTPM instance required!\n"));
861 return EFI_UNSUPPORTED
;
864 Status
= PublishAcpiTable ();
865 ASSERT_EFI_ERROR (Status
);
868 // Get the Sw dispatch protocol and register SMI callback functions.
870 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid
, NULL
, (VOID
**)&SwDispatch
);
871 ASSERT_EFI_ERROR (Status
);
872 SwContext
.SwSmiInputValue
= (UINTN
) -1;
873 Status
= SwDispatch
->Register (SwDispatch
, PhysicalPresenceCallback
, &SwContext
, &SwHandle
);
874 ASSERT_EFI_ERROR (Status
);
875 if (EFI_ERROR (Status
)) {
878 mTcgNvs
->PhysicalPresence
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
880 SwContext
.SwSmiInputValue
= (UINTN
) -1;
881 Status
= SwDispatch
->Register (SwDispatch
, MemoryClearCallback
, &SwContext
, &SwHandle
);
882 ASSERT_EFI_ERROR (Status
);
883 if (EFI_ERROR (Status
)) {
886 mTcgNvs
->MemoryClear
.SoftwareSmi
= (UINT8
) SwContext
.SwSmiInputValue
;
889 // Locate SmmVariableProtocol.
891 Status
= gSmst
->SmmLocateProtocol (&gEfiSmmVariableProtocolGuid
, NULL
, (VOID
**)&mSmmVariable
);
892 ASSERT_EFI_ERROR (Status
);
895 // Set TPM2 ACPI table
897 Status
= PublishTpm2 ();
898 ASSERT_EFI_ERROR (Status
);