\r
PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.\r
\r
-Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
This program and the accompanying materials \r
are licensed and made available under the terms and conditions of the BSD License \r
which accompanies this distribution. The full text of the license may be found at \r
\r
#include "Tcg2Smm.h"\r
\r
-typedef enum {\r
- PtpInterfaceTis,\r
- PtpInterfaceFifo,\r
- PtpInterfaceCrb,\r
- PtpInterfaceMax,\r
-} PTP_INTERFACE_TYPE;\r
-\r
-/**\r
- Return PTP interface type.\r
-\r
- @param[in] Register Pointer to PTP register.\r
-\r
- @return PTP interface type.\r
-**/\r
-PTP_INTERFACE_TYPE\r
-GetPtpInterface (\r
- IN VOID *Register\r
- )\r
-{\r
- PTP_CRB_INTERFACE_IDENTIFIER InterfaceId;\r
- PTP_FIFO_INTERFACE_CAPABILITY InterfaceCapability;\r
-\r
- //\r
- // Check interface id\r
- //\r
- InterfaceId.Uint32 = MmioRead32 ((UINTN)&((PTP_CRB_REGISTERS *)Register)->InterfaceId);\r
- InterfaceCapability.Uint32 = MmioRead32 ((UINTN)&((PTP_FIFO_REGISTERS *)Register)->InterfaceCapability);\r
-\r
- if (InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_TIS) {\r
- return PtpInterfaceTis;\r
- }\r
-\r
- if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_CRB) &&\r
- (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_CRB) &&\r
- (InterfaceId.Bits.CapCRB != 0)) {\r
- return PtpInterfaceCrb;\r
- }\r
-\r
- if ((InterfaceId.Bits.InterfaceType == PTP_INTERFACE_IDENTIFIER_INTERFACE_TYPE_FIFO) &&\r
- (InterfaceId.Bits.InterfaceVersion == PTP_INTERFACE_IDENTIFIER_INTERFACE_VERSION_FIFO) &&\r
- (InterfaceId.Bits.CapFIFO != 0) &&\r
- (InterfaceCapability.Bits.InterfaceVersion == INTERFACE_CAPABILITY_INTERFACE_VERSION_PTP)) {\r
- return PtpInterfaceFifo;\r
- }\r
-\r
- //\r
- // No Ptp interface available\r
- //\r
- return PtpInterfaceMax;\r
-}\r
\r
EFI_TPM2_ACPI_TABLE mTpm2AcpiTemplate = {\r
{\r
return EFI_NOT_FOUND;\r
}\r
\r
+/**\r
+ Patch interrupt resources returned by TPM _PRS. ResourceTemplate to patch is determined by input\r
+ interrupt buffer size. BufferSize, PkgLength and interrupt descirptor in ByteList need to be patched\r
+\r
+ @param[in, out] Table The TPM item in ACPI table.\r
+ @param[in] IrqBuffer Input new IRQ buffer.\r
+ @param[in] IrqBuffserSize Input new IRQ buffer size.\r
+ @param[out] IsShortFormPkgLength If _PRS returns Short length Package(ACPI spec 20.2.4).\r
+\r
+ @return patch status.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdatePossibleResource (\r
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER *Table,\r
+ IN UINT32 *IrqBuffer,\r
+ IN UINT32 IrqBuffserSize,\r
+ OUT BOOLEAN *IsShortFormPkgLength\r
+ )\r
+{\r
+ UINT8 *DataPtr;\r
+ UINT8 *DataEndPtr;\r
+ UINT32 NewPkgLength;\r
+ UINT32 OrignalPkgLength;\r
+\r
+ NewPkgLength = 0;\r
+ OrignalPkgLength = 0;\r
+ DataEndPtr = NULL;\r
+\r
+ //\r
+ // Follow ACPI spec\r
+ // 6.4.3 Extend Interrupt Descriptor.\r
+ // 19.3.3 ASL Resource Template\r
+ // 20 AML specification\r
+ // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag\r
+ //\r
+ // AML data is organized by following rule.\r
+ // Code need to patch BufferSize and PkgLength and interrupt descirptor in ByteList\r
+ //\r
+ // ============= Buffer ====================\r
+ // DefBuffer := BufferOp PkgLength BufferSize ByteList\r
+ // BufferOp := 0x11\r
+ //\r
+ // ==============PkgLength==================\r
+ // PkgLength := PkgLeadByte |\r
+ // <PkgLeadByte ByteData> |\r
+ // <PkgLeadByte ByteData ByteData> |\r
+ // <PkgLeadByte ByteData ByteData ByteData>\r
+ //\r
+ // PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>\r
+ // <bit 5-4: Only used if PkgLength <= 63 >\r
+ // <bit 3-0: Least significant package length nybble>\r
+ //\r
+ //==============BufferSize==================\r
+ // BufferSize := Integar\r
+ // Integar := ByteConst|WordConst|DwordConst....\r
+ //\r
+ // ByteConst := BytePrefix ByteData\r
+ //\r
+ //==============ByteList===================\r
+ // ByteList := ByteData ByteList\r
+ //\r
+ //=========================================\r
+\r
+ //\r
+ // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching\r
+ //\r
+ for (DataPtr = (UINT8 *)(Table + 1);\r
+ DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE));\r
+ DataPtr += 1) {\r
+ if (CompareMem(DataPtr, TPM_PRS_RESS, TPM_PRS_RES_NAME_SIZE) == 0) {\r
+ //\r
+ // Jump over object name & BufferOp\r
+ //\r
+ DataPtr += TPM_PRS_RES_NAME_SIZE + 1;\r
+\r
+ if ((*DataPtr & (BIT7|BIT6)) == 0) {\r
+ OrignalPkgLength = (UINT32)*DataPtr;\r
+ DataEndPtr = DataPtr + OrignalPkgLength;\r
+\r
+ //\r
+ // Jump over PkgLength = PkgLeadByte only\r
+ //\r
+ NewPkgLength++;\r
+\r
+ //\r
+ // Jump over BufferSize\r
+ //\r
+ if (*(DataPtr + 1) == AML_BYTE_PREFIX) {\r
+ NewPkgLength += 2;\r
+ } else if (*(DataPtr + 1) == AML_WORD_PREFIX) {\r
+ NewPkgLength += 3;\r
+ } else if (*(DataPtr + 1) == AML_DWORD_PREFIX) {\r
+ NewPkgLength += 5;\r
+ } else {\r
+ ASSERT(FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ } else {\r
+ ASSERT(FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)\r
+ //\r
+ NewPkgLength += 19 + IrqBuffserSize;\r
+ if (NewPkgLength > 63) {\r
+ break;\r
+ }\r
+\r
+ if (NewPkgLength > OrignalPkgLength) {\r
+ ASSERT(FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // 1.1 Patch PkgLength\r
+ //\r
+ *DataPtr = (UINT8)NewPkgLength;\r
+\r
+ //\r
+ // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).\r
+ // It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit.\r
+ //\r
+ *(DataPtr + 2) = (UINT8)(IrqBuffserSize + 19);\r
+\r
+ //\r
+ // Notify _PRS to report short formed ResourceTemplate\r
+ //\r
+ *IsShortFormPkgLength = TRUE;\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ //\r
+ // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching\r
+ //\r
+ if (NewPkgLength > 63) {\r
+ NewPkgLength = 0;\r
+ OrignalPkgLength = 0;\r
+ for (DataPtr = (UINT8 *)(Table + 1);\r
+ DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE));\r
+ DataPtr += 1) {\r
+ if (CompareMem(DataPtr, TPM_PRS_RESL, TPM_PRS_RES_NAME_SIZE) == 0) {\r
+ //\r
+ // Jump over object name & BufferOp\r
+ //\r
+ DataPtr += TPM_PRS_RES_NAME_SIZE + 1;\r
+\r
+ if ((*DataPtr & (BIT7|BIT6)) != 0) {\r
+ OrignalPkgLength = (UINT32)(*(DataPtr + 1) << 4) + (*DataPtr & 0x0F);\r
+ DataEndPtr = DataPtr + OrignalPkgLength;\r
+ //\r
+ // Jump over PkgLength = PkgLeadByte + ByteData length\r
+ //\r
+ NewPkgLength += 1 + ((*DataPtr & (BIT7|BIT6)) >> 6);\r
+\r
+ //\r
+ // Jump over BufferSize\r
+ //\r
+ if (*(DataPtr + NewPkgLength) == AML_BYTE_PREFIX) {\r
+ NewPkgLength += 2;\r
+ } else if (*(DataPtr + NewPkgLength) == AML_WORD_PREFIX) {\r
+ NewPkgLength += 3;\r
+ } else if (*(DataPtr + NewPkgLength) == AML_DWORD_PREFIX) {\r
+ NewPkgLength += 5;\r
+ } else {\r
+ ASSERT(FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+ } else {\r
+ ASSERT(FALSE);\r
+ return EFI_UNSUPPORTED;\r
+ }\r
+\r
+ //\r
+ // Include Memory32Fixed Descritor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)\r
+ //\r
+ NewPkgLength += 19 + IrqBuffserSize;\r
+\r
+ if (NewPkgLength > OrignalPkgLength) {\r
+ ASSERT(FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData\r
+ //\r
+ *DataPtr = (UINT8)((*DataPtr) & 0xF0) | (NewPkgLength & 0x0F);\r
+ *(DataPtr + 1) = (UINT8)((NewPkgLength & 0xFF0) >> 4);\r
+\r
+ //\r
+ // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descritor + Interrupt Descriptor + End Tag).\r
+ // It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit.\r
+ //\r
+ *(DataPtr + 2 + ((*DataPtr & (BIT7|BIT6)) >> 6)) = (UINT8)(IrqBuffserSize + 19);\r
+\r
+ //\r
+ // Notify _PRS to report long formed ResourceTemplate\r
+ //\r
+ *IsShortFormPkgLength = FALSE;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (DataPtr >= (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE))) {\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ //\r
+ // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor.\r
+ // 5 bytes for interrupt descriptor header, 2 bytes for End Tag\r
+ //\r
+ DataPtr += NewPkgLength - (5 + IrqBuffserSize + 2);\r
+ //\r
+ // 3.1 Patch Length bit[7:0] of Interrupt descirptor patch interrupt descriptor\r
+ //\r
+ *(DataPtr + 1) = (UINT8)(2 + IrqBuffserSize);\r
+ //\r
+ // 3.2 Patch Interrupt Table Length\r
+ //\r
+ *(DataPtr + 4) = (UINT8)(IrqBuffserSize / sizeof(UINT32));\r
+ //\r
+ // 3.3 Copy patched InterruptNumBuffer\r
+ //\r
+ CopyMem(DataPtr + 5, IrqBuffer, IrqBuffserSize);\r
+\r
+ //\r
+ // 4. Jump over Interrupt descirptor and Patch END Tag, set Checksum field to 0\r
+ //\r
+ DataPtr += 5 + IrqBuffserSize;\r
+ *DataPtr = ACPI_END_TAG_DESCRIPTOR;\r
+ *(DataPtr + 1) = 0;\r
+\r
+ //\r
+ // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP\r
+ //\r
+ DataPtr += 2;\r
+ if (DataPtr < DataEndPtr) {\r
+ SetMem(DataPtr, (UINTN)DataEndPtr - (UINTN)DataPtr, AML_NOOP_OP);\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
/**\r
Patch TPM2 device HID string. The initial string tag in TPM2 ACPI table is "NNN0000".\r
\r
UINTN TableKey;\r
EFI_ACPI_DESCRIPTION_HEADER *Table;\r
UINTN TableSize;\r
+ UINT32 *PossibleIrqNumBuf;\r
+ UINT32 PossibleIrqNumBufSize;\r
+ BOOLEAN IsShortFormPkgLength;\r
+\r
+ IsShortFormPkgLength = FALSE;\r
\r
Status = GetSectionFromFv (\r
&gEfiCallerIdGuid,\r
return Status;\r
}\r
\r
+ if (PcdGet32(PcdTpm2CurrentIrqNum) != 0) {\r
+ //\r
+ // Patch _PRS interrupt resource only when TPM interrupt is supported\r
+ //\r
+ PossibleIrqNumBuf = (UINT32 *)PcdGetPtr(PcdTpm2PossibleIrqNumBuf);\r
+ PossibleIrqNumBufSize = (UINT32)PcdGetSize(PcdTpm2PossibleIrqNumBuf);\r
+\r
+ if (PossibleIrqNumBufSize <= MAX_PRS_INT_BUF_SIZE && (PossibleIrqNumBufSize % sizeof(UINT32)) == 0) {\r
+ Status = UpdatePossibleResource(Table, PossibleIrqNumBuf, PossibleIrqNumBufSize, &IsShortFormPkgLength);\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",\r
+ Status\r
+ ));\r
+ } else {\r
+ DEBUG ((\r
+ DEBUG_INFO,\r
+ "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",\r
+ PossibleIrqNumBufSize\r
+ ));\r
+ }\r
+ }\r
+\r
//\r
// Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
//\r
CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );\r
mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));\r
ASSERT (mTcgNvs != NULL);\r
+ mTcgNvs->TpmIrqNum = PcdGet32(PcdTpm2CurrentIrqNum);\r
+ mTcgNvs->IsShortFormPkgLength = IsShortFormPkgLength;\r
\r
//\r
// Publish the TPM ACPI table. Table is re-checksumed.\r
UINTN TableKey;\r
UINT64 OemTableId;\r
EFI_TPM2_ACPI_CONTROL_AREA *ControlArea;\r
- PTP_INTERFACE_TYPE InterfaceType;\r
+ TPM2_PTP_INTERFACE_TYPE InterfaceType;\r
\r
mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev);\r
DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision));\r
\r
+ //\r
+ // PlatformClass is only valid for version 4 and above\r
+ // BIT0~15: PlatformClass \r
+ // BIT16~31: Reserved\r
+ //\r
+ if (mTpm2AcpiTemplate.Header.Revision >= EFI_TPM2_ACPI_TABLE_REVISION_4) {\r
+ mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass);\r
+ DEBUG((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF)));\r
+ }\r
+\r
//\r
// Measure to PCR[0] with event EV_POST_CODE ACPI DATA\r
//\r
sizeof(mTpm2AcpiTemplate)\r
);\r
\r
- InterfaceType = GetPtpInterface ((VOID *) (UINTN) PcdGet64 (PcdTpmBaseAddress));\r
+ InterfaceType = PcdGet8(PcdActiveTpmInterfaceType);\r
switch (InterfaceType) {\r
- case PtpInterfaceCrb:\r
+ case Tpm2PtpInterfaceCrb:\r
mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE;\r
mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40;\r
ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea;\r
ControlArea->Command = PcdGet64 (PcdTpmBaseAddress) + 0x80;\r
ControlArea->Response = PcdGet64 (PcdTpmBaseAddress) + 0x80;\r
break;\r
- case PtpInterfaceFifo:\r
- case PtpInterfaceTis:\r
+ case Tpm2PtpInterfaceFifo:\r
+ case Tpm2PtpInterfaceTis:\r
break;\r
default:\r
DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType));\r