/** @file Tpm2 device table generating Library Copyright (c) 2025, Arm Limited. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent @par Reference(s): - TCG ACPI specification. (https://trustedcomputinggroup.org/resource/tcg-acpi-specification/) **/ #include #include #include #include #include #include #include #include // Module specific include files. #include #include #include #include #include #include /** C array containing the compiled AML template. This symbol is defined in the auto generated C file containing the AML bytecode array. */ extern CHAR8 tpm2devicetabletemplate_aml_code[]; /** Fixup the TPM2 device UID (_UID). @param [in] RootNodeHandle Pointer to the root of an AML tree. @param [in] Uid UID for the TPM2 device. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER Invalid parameter. @retval EFI_NOT_FOUND Could not find information. @retval EFI_OUT_OF_RESOURCES Out of resources. **/ STATIC EFI_STATUS EFIAPI FixupTpm2DeviceUid ( IN AML_ROOT_NODE_HANDLE RootNodeHandle, IN CONST UINT64 Uid ) { EFI_STATUS Status; AML_OBJECT_NODE_HANDLE NameOpIdNode; // Get the _UID NameOp object defined by the "Name ()" statement, // and update its value. Status = AmlFindNode ( RootNodeHandle, "\\_SB_.TPM0._UID", &NameOpIdNode ); if (EFI_ERROR (Status)) { return Status; } return AmlNameOpUpdateInteger (NameOpIdNode, (UINT64)Uid); } /** Fixup the Tpm2 device name. @param [in] RootNodeHandle Pointer to the root of an AML tree. @param [in] Name The Name to give to the Device. Must be a NULL-terminated ASL NameString e.g.: "DEV0", "DV15.DEV0", etc. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER Invalid parameter. @retval EFI_NOT_FOUND Could not find information. @retval EFI_OUT_OF_RESOURCES Out of resources. **/ STATIC EFI_STATUS EFIAPI FixupTpm2DeviceName ( IN AML_ROOT_NODE_HANDLE RootNodeHandle, IN CONST CHAR8 *Name ) { EFI_STATUS Status; AML_OBJECT_NODE_HANDLE DeviceNode; // Get the COM0 variable defined by the "Device ()" statement. Status = AmlFindNode (RootNodeHandle, "\\_SB_.TPM0", &DeviceNode); if (EFI_ERROR (Status)) { return Status; } // Update the Device's name. return AmlDeviceOpUpdateName (DeviceNode, Name); } /** Fixup the Tpm2 device _CRS values (BaseAddress, ...). @param [in] RootNodeHandle Pointer to the root of an AML tree. @param [in] TpmDevInfo Pointer to a TPM2 device Information structure. Get the device size Information from there. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER Invalid parameter. @retval EFI_NOT_FOUND Could not find information. @retval EFI_OUT_OF_RESOURCES Out of resources. **/ STATIC EFI_STATUS EFIAPI FixupTpm2DeviceCrs ( IN AML_ROOT_NODE_HANDLE RootNodeHandle, IN CONST CM_ARCH_COMMON_TPM2_DEVICE_INFO *TpmDevInfo ) { EFI_STATUS Status; AML_OBJECT_NODE_HANDLE NameOpCrsNode; AML_DATA_NODE_HANDLE QWordRdNode; // Get the "_CRS" object defined by the "Name ()" statement. Status = AmlFindNode ( RootNodeHandle, "\\_SB_.TPM0._CRS", &NameOpCrsNode ); if (EFI_ERROR (Status)) { return Status; } // Get the first Rd node in the "_CRS" object. Status = AmlNameOpGetFirstRdNode (NameOpCrsNode, &QWordRdNode); if (EFI_ERROR (Status)) { return Status; } if (QWordRdNode == NULL) { return EFI_INVALID_PARAMETER; } // Update the TPM2 device's base address and length. Status = AmlUpdateRdQWord ( QWordRdNode, TpmDevInfo->Tpm2DeviceBaseAddress, TpmDevInfo->Tpm2DeviceSize ); if (EFI_ERROR (Status)) { return Status; } return Status; } /** Fixup the Tpm2 Device in the AML tree. For each template value: - find the node to update; - update the value. @param [in] RootNodeHandle Pointer to the root of the AML tree. @param [in] TpmDevInfo Pointer to a TPM2 device Information structure. @param [in] Name The Name to give to the Device. Must be a NULL-terminated ASL NameString e.g.: "DEV0", "DV15.DEV0", etc. @param [in] Uid UID for the TPM2 device. @retval EFI_SUCCESS The function completed successfully. @retval EFI_INVALID_PARAMETER Invalid parameter. @retval EFI_NOT_FOUND Could not find information. @retval EFI_OUT_OF_RESOURCES Out of resources. **/ STATIC EFI_STATUS EFIAPI FixupTpm2DeviceInfo ( IN AML_ROOT_NODE_HANDLE RootNodeHandle, IN CONST CM_ARCH_COMMON_TPM2_DEVICE_INFO *TpmDevInfo, IN CONST CHAR8 *Name, IN CONST UINT64 Uid ) { EFI_STATUS Status; ASSERT (RootNodeHandle != NULL); ASSERT (TpmDevInfo != NULL); ASSERT (Name != NULL); // Fixup the _UID value. Status = FixupTpm2DeviceUid (RootNodeHandle, Uid); if (EFI_ERROR (Status)) { return Status; } // Fixup the _CRS values. Status = FixupTpm2DeviceCrs (RootNodeHandle, TpmDevInfo); if (EFI_ERROR (Status)) { return Status; } // Fixup the Tpm2 device name. // This MUST be done at the end, otherwise AML paths won't be valid anymore. return FixupTpm2DeviceName (RootNodeHandle, Name); } /** Build a SSDT table describing the TPM2 device. The table created by this function must be freed by FreeSImpleTpm2DeviceTable. @param [in] TpmDevInfo TPM2 device info to describe in the SSDT table. @param [in] Name The Name to give to the Device. Must be a NULL-terminated ASL NameString e.g.: "DEV0", "DV15.DEV0", etc. @param [in] Uid UID for the TPM2 device @param [out] Table If success, pointer to the created SSDT table. @retval EFI_SUCCESS Table generated successfully. @retval EFI_INVALID_PARAMETER A parameter is invalid. @retval EFI_NOT_FOUND Could not find information. @retval EFI_OUT_OF_RESOURCES Could not allocate memory. **/ EFI_STATUS EFIAPI BuildTpm2DeviceTable ( IN CONST CM_ARCH_COMMON_TPM2_DEVICE_INFO *TpmDevInfo, IN CONST CHAR8 *Name, IN CONST UINT64 Uid, OUT EFI_ACPI_DESCRIPTION_HEADER **Table ) { EFI_STATUS Status; EFI_STATUS Status1; AML_ROOT_NODE_HANDLE RootNodeHandle; ASSERT (TpmDevInfo != NULL); ASSERT (Name != NULL); ASSERT (Table != NULL); // Parse the Tpm2 Device Table Template. Status = AmlParseDefinitionBlock ( (EFI_ACPI_DESCRIPTION_HEADER *)tpm2devicetabletemplate_aml_code, &RootNodeHandle ); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "ERROR: TPM2-DEVICE-FIXUP:" " Failed to parse SSDT TPM2 device Template. Status = %r\n", Status )); return Status; } // Fixup the template values. Status = FixupTpm2DeviceInfo ( RootNodeHandle, TpmDevInfo, Name, Uid ); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "ERROR: TPM2-DEVICE-FIXUP: Failed to fixup SSDT TPM2 Device Table." " Status = %r\n", Status )); goto ExitHandler; } // Serialize the tree. Status = AmlSerializeDefinitionBlock ( RootNodeHandle, Table ); if (EFI_ERROR (Status)) { DEBUG (( DEBUG_ERROR, "ERROR: TPM2-DEVICE-FIXUP: Failed to Serialize SSDT Table Data." " Status = %r\n", Status )); } ExitHandler: // Cleanup if (RootNodeHandle != NULL) { Status1 = AmlDeleteTree (RootNodeHandle); if (EFI_ERROR (Status1)) { DEBUG (( DEBUG_ERROR, "ERROR: TPM2-DEVICE-FIXUP: Failed to cleanup AML tree." " Status = %r\n", Status1 )); // If Status was success but we failed to delete the AML Tree // return Status1 else return the original error code, i.e. Status. if (!EFI_ERROR (Status)) { return Status1; } } } return Status; } /** Free an Tpm2 device table previously created by the BuildTpm2DeviceTable function. @param [in] Table Pointer to a Tpm2 Device table allocated by the BuildTpm2DeviceTable function. **/ VOID EFIAPI FreeTpm2DeviceTable ( IN EFI_ACPI_DESCRIPTION_HEADER *Table ) { ASSERT (Table != NULL); FreePool (Table); }