+/**\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
+\r
+ @return patch status.\r
+\r
+**/\r
+EFI_STATUS\r
+UpdatePossibleResource (\r
+ EFI_ACPI_DESCRIPTION_HEADER *Table,\r
+ UINT32 *IrqBuffer,\r
+ UINT32 IrqBuffserSize\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
+ mTcgNvs->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
+ mTcgNvs->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 whole ResourceTemplate. Stuff rest bytes to NOOP\r
+ //\r
+ for (DataPtr += 2; DataPtr < DataEndPtr; DataPtr++) {\r
+ *DataPtr = AML_NOOP_OP;\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r