[PATCH v3] tpm: Get TCG log from TPM2 ACPI table for tpm2 systems

From: Jordan Hand
Date: Mon Jun 24 2019 - 13:47:52 EST


From: Jordan Hand <jordanhand22@xxxxxxxxx>

For TPM2-based systems, retrieve the TCG log from the TPM2 ACPI table.
The TPM2 ACPI table is defined in section 7.3 of the TCG ACPI
Specification (see link).

The TPM2 table is used primarily by legacy BIOS in place of the TCPA table
when the system's TPM is version 2.0 to denote (among other metadata) the
location of the crypto-agile TCG log. In particluar, the SeaBios firmware
used by default by QEMU makes use of this table for crypto-agile logs.

Link: https://trustedcomputinggroup.org/wp-content/uploads/TCG_ACPIGeneralSpecification_v1.20_r8.pdf

Signed-off-by: Jordan Hand <jordanhand22@xxxxxxxxx>
---

Same as v2 with more descriptive commit message

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..b945c4ff3af6 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(struct 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.17.1