For TPM2-based systems, retrieve the TCG log from the TPM2 ACPI table.

Signed-off-by: Jordan Hand <jordanhan...@gmail.com>
---
 drivers/char/tpm/eventlog/acpi.c | 67 +++++++++++++++++++++++---------
 1 file changed, 48 insertions(+), 19 deletions(-)

diff --git a/drivers/char/tpm/eventlog/acpi.c b/drivers/char/tpm/eventlog/acpi.c
index 63ada5e53f13..942d282e2738 100644
--- a/drivers/char/tpm/eventlog/acpi.c
+++ b/drivers/char/tpm/eventlog/acpi.c
@@ -41,17 +41,31 @@ struct acpi_tcpa {
        };
 };
 
+struct acpi_tpm2 {
+       struct acpi_table_header hdr;
+       u16 platform_class;
+       u16 reserved;
+       u64 control_area_addr;
+       u32 start_method;
+       u8 start_method_params[12];
+       u32 log_max_len;
+       u64 log_start_addr;
+} __packed;
+
 /* read binary bios log */
 int tpm_read_log_acpi(struct tpm_chip *chip)
 {
-       struct acpi_tcpa *buff;
+       struct acpi_table_header *buff;
+       struct acpi_tcpa *tcpa;
+       struct acpi_tpm2 *tpm2;
+
        acpi_status status;
        void __iomem *virt;
        u64 len, start;
+       int log_type;
        struct tpm_bios_log *log;
-
-       if (chip->flags & TPM_CHIP_FLAG_TPM2)
-               return -ENODEV;
+       bool is_tpm2 = chip->flags & TPM_CHIP_FLAG_TPM2;
+       acpi_string table_sig;
 
        log = &chip->log;
 
@@ -61,26 +75,41 @@ int tpm_read_log_acpi(struct tpm_chip *chip)
        if (!chip->acpi_dev_handle)
                return -ENODEV;
 
-       /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
-       status = acpi_get_table(ACPI_SIG_TCPA, 1,
-                               (struct acpi_table_header **)&buff);
+       /* Find TCPA or TPM2 entry in RSDT (ACPI_LOGICAL_ADDRESSING) */
+       table_sig = is_tpm2 ? ACPI_SIG_TPM2 : ACPI_SIG_TCPA;
+       status = acpi_get_table(table_sig, 1, &buff);
 
        if (ACPI_FAILURE(status))
                return -ENODEV;
 
-       switch(buff->platform_class) {
-       case BIOS_SERVER:
-               len = buff->server.log_max_len;
-               start = buff->server.log_start_addr;
-               break;
-       case BIOS_CLIENT:
-       default:
-               len = buff->client.log_max_len;
-               start = buff->client.log_start_addr;
-               break;
+       /* If log_max_len and log_start_addr are set, start_method_params will
+        * be 12 bytes, according to TCG ACPI spec. If start_method_params is
+        * fewer than 12 bytes, the TCG log is not available
+        */
+       if (is_tpm2 && (buff->length == sizeof(acpi_tpm2))) {
+               tpm2 = (struct acpi_tpm2 *)buff;
+               len = tpm2->log_max_len;
+               start = tpm2->log_start_addr;
+               log_type = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2;
+       } else {
+               tcpa = (struct acpi_tcpa *)buff;
+               switch (tcpa->platform_class) {
+               case BIOS_SERVER:
+                       len = tcpa->server.log_max_len;
+                       start = tcpa->server.log_start_addr;
+                       break;
+               case BIOS_CLIENT:
+               default:
+                       len = tcpa->client.log_max_len;
+                       start = tcpa->client.log_start_addr;
+                       break;
+               }
+               log_type = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
        }
+
        if (!len) {
-               dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__);
+               dev_warn(&chip->dev, "%s: %s log area empty\n",
+                               table_sig, __func__);
                return -EIO;
        }
 
@@ -98,7 +127,7 @@ int tpm_read_log_acpi(struct tpm_chip *chip)
        memcpy_fromio(log->bios_event_log, virt, len);
 
        acpi_os_unmap_iomem(virt, len);
-       return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2;
+       return log_type;
 
 err:
        kfree(log->bios_event_log);
-- 
2.20.1

Reply via email to