-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 descriptor 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 := Integer\r
- // Integer := 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 Descriptor (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 Descriptor + 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 Descriptor (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 Descriptor + 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 descriptor 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 descriptor 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
- @param[in, out] Table The TPM2 SSDT ACPI table.\r
-\r
- @return HID Update status.\r
-\r
-**/\r
-EFI_STATUS\r
-UpdateHID (\r
- EFI_ACPI_DESCRIPTION_HEADER *Table\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT8 *DataPtr;\r
- CHAR8 Hid[TPM_HID_ACPI_SIZE];\r
- UINT32 ManufacturerID;\r
- UINT32 FirmwareVersion1;\r
- UINT32 FirmwareVersion2;\r
- BOOLEAN PnpHID;\r
-\r
- PnpHID = TRUE;\r
-\r
- //\r
- // Initialize HID with Default PNP string\r
- //\r
- ZeroMem(Hid, TPM_HID_ACPI_SIZE);\r
-\r
- //\r
- // Get Manufacturer ID\r
- //\r
- Status = Tpm2GetCapabilityManufactureID(&ManufacturerID);\r
- if (!EFI_ERROR(Status)) {\r
- DEBUG((EFI_D_INFO, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID));\r
- //\r
- // ManufacturerID defined in TCG Vendor ID Registry\r
- // may tailed with 0x00 or 0x20\r
- //\r
- if ((ManufacturerID >> 24) == 0x00 || ((ManufacturerID >> 24) == 0x20)) {\r
- //\r
- // HID containing PNP ID "NNN####"\r
- // NNN is uppercase letter for Vendor ID specified by manufacturer\r
- //\r
- CopyMem(Hid, &ManufacturerID, 3);\r
- } else {\r
- //\r
- // HID containing ACP ID "NNNN####"\r
- // NNNN is uppercase letter for Vendor ID specified by manufacturer\r
- //\r
- CopyMem(Hid, &ManufacturerID, 4);\r
- PnpHID = FALSE;\r
- }\r
- } else {\r
- DEBUG ((EFI_D_ERROR, "Get TPM_PT_MANUFACTURER failed %x!\n", Status));\r
- ASSERT(FALSE);\r
- return Status;\r
- }\r
-\r
- Status = Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1, &FirmwareVersion2);\r
- if (!EFI_ERROR(Status)) {\r
- DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1));\r
- DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2));\r
- //\r
- // #### is Firmware Version 1\r
- //\r
- if (PnpHID) {\r
- AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));\r
- } else {\r
- AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));\r
- }\r
-\r
- } else {\r
- DEBUG ((EFI_D_ERROR, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status));\r
- ASSERT(FALSE);\r
- return Status;\r
- }\r
-\r
- //\r
- // Patch HID in ASL code before loading the SSDT.\r
- //\r
- for (DataPtr = (UINT8 *)(Table + 1);\r
- DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - TPM_HID_PNP_SIZE);\r
- DataPtr += 1) {\r
- if (AsciiStrCmp((CHAR8 *)DataPtr, TPM_HID_TAG) == 0) {\r
- if (PnpHID) {\r
- CopyMem(DataPtr, Hid, TPM_HID_PNP_SIZE);\r
- //\r
- // if HID is PNP ID, patch the last byte in HID TAG to Noop\r
- //\r
- *(DataPtr + TPM_HID_PNP_SIZE) = AML_NOOP_OP;\r
- } else {\r
-\r
- CopyMem(DataPtr, Hid, TPM_HID_ACPI_SIZE);\r
- }\r
- DEBUG((DEBUG_INFO, "TPM2 ACPI _HID is patched to %a\n", DataPtr));\r
-\r
- return Status;\r
- }\r
- }\r
-\r
- DEBUG((EFI_D_ERROR, "TPM2 ACPI HID TAG for patch not found!\n"));\r
- return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
- Initialize and publish TPM items in ACPI table.\r
-\r
- @retval EFI_SUCCESS The TCG ACPI table is published successfully.\r
- @retval Others The TCG ACPI table is not published.\r
-\r
-**/\r
-EFI_STATUS\r
-PublishAcpiTable (\r
- VOID\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_ACPI_TABLE_PROTOCOL *AcpiTable;\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
- EFI_SECTION_RAW,\r
- 0,\r
- (VOID **) &Table,\r
- &TableSize\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- //\r
- // Measure to PCR[0] with event EV_POST_CODE ACPI DATA.\r
- // The measurement has to be done before any update.\r
- // Otherwise, the PCR record would be different after TPM FW update\r
- // or the PCD configuration change.\r
- //\r
- TpmMeasureAndLogData(\r
- 0,\r
- EV_POST_CODE,\r
- EV_POSTCODE_INFO_ACPI_DATA,\r
- ACPI_DATA_LEN,\r
- Table,\r
- TableSize\r
- );\r
-\r
- //\r
- // Update Table version before measuring it to PCR\r
- //\r
- Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer));\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- DEBUG ((\r
- DEBUG_INFO,\r
- "Current physical presence interface version - %a\n",\r
- (CHAR8 *) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer)\r
- ));\r
-\r
- //\r
- // Update TPM2 HID after measuring it to PCR\r
- //\r
- Status = UpdateHID(Table);\r
- if (EFI_ERROR(Status)) {\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
- ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));\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-checksummed.\r
- //\r
- Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- TableKey = 0;\r
- Status = AcpiTable->InstallAcpiTable (\r
- AcpiTable,\r
- Table,\r
- TableSize,\r
- &TableKey\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- Publish TPM2 ACPI table\r
-\r
- @retval EFI_SUCCESS The TPM2 ACPI table is published successfully.\r
- @retval Others The TPM2 ACPI table is not published.\r
-\r
-**/\r
-EFI_STATUS\r
-PublishTpm2 (\r
- VOID\r
- )\r