| /** @file | |
| Tpm2 device table generating Library | |
| Copyright (c) 2025, Arm Limited. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| @par Reference(s): | |
| - TCG ACPI specification. | |
| (https://trustedcomputinggroup.org/resource/tcg-acpi-specification/) | |
| **/ | |
| #include <IndustryStandard/DebugPort2Table.h> | |
| #include <Library/AcpiLib.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/PcdLib.h> | |
| #include <Protocol/AcpiTable.h> | |
| // Module specific include files. | |
| #include <AcpiTableGenerator.h> | |
| #include <ConfigurationManagerObject.h> | |
| #include <ConfigurationManagerHelper.h> | |
| #include <Library/AcpiHelperLib.h> | |
| #include <Library/AmlLib/AmlLib.h> | |
| #include <Protocol/ConfigurationManagerProtocol.h> | |
| /** 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); | |
| } |