| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Copyright (C) 2005 IBM Corporation |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 11 | 12 | * Maintained by: <tpmdd-devel@lists.sourceforge.net> |
|---|
| 12 | 13 | * |
|---|
| 13 | 14 | * Access to the event log extended by the TCG BIOS of PC platform |
|---|
| 14 | | - * |
|---|
| 15 | | - * This program is free software; you can redistribute it and/or |
|---|
| 16 | | - * modify it under the terms of the GNU General Public License |
|---|
| 17 | | - * as published by the Free Software Foundation; either version |
|---|
| 18 | | - * 2 of the License, or (at your option) any later version. |
|---|
| 19 | | - * |
|---|
| 20 | 15 | */ |
|---|
| 21 | 16 | |
|---|
| 22 | 17 | #include <linux/seq_file.h> |
|---|
| .. | .. |
|---|
| 46 | 41 | }; |
|---|
| 47 | 42 | }; |
|---|
| 48 | 43 | |
|---|
| 44 | +/* Check that the given log is indeed a TPM2 log. */ |
|---|
| 45 | +static bool tpm_is_tpm2_log(void *bios_event_log, u64 len) |
|---|
| 46 | +{ |
|---|
| 47 | + struct tcg_efi_specid_event_head *efispecid; |
|---|
| 48 | + struct tcg_pcr_event *event_header; |
|---|
| 49 | + int n; |
|---|
| 50 | + |
|---|
| 51 | + if (len < sizeof(*event_header)) |
|---|
| 52 | + return false; |
|---|
| 53 | + len -= sizeof(*event_header); |
|---|
| 54 | + event_header = bios_event_log; |
|---|
| 55 | + |
|---|
| 56 | + if (len < sizeof(*efispecid)) |
|---|
| 57 | + return false; |
|---|
| 58 | + efispecid = (struct tcg_efi_specid_event_head *)event_header->event; |
|---|
| 59 | + |
|---|
| 60 | + n = memcmp(efispecid->signature, TCG_SPECID_SIG, |
|---|
| 61 | + sizeof(TCG_SPECID_SIG)); |
|---|
| 62 | + return n == 0; |
|---|
| 63 | +} |
|---|
| 64 | + |
|---|
| 49 | 65 | /* read binary bios log */ |
|---|
| 50 | 66 | int tpm_read_log_acpi(struct tpm_chip *chip) |
|---|
| 51 | 67 | { |
|---|
| .. | .. |
|---|
| 54 | 70 | void __iomem *virt; |
|---|
| 55 | 71 | u64 len, start; |
|---|
| 56 | 72 | struct tpm_bios_log *log; |
|---|
| 57 | | - |
|---|
| 58 | | - if (chip->flags & TPM_CHIP_FLAG_TPM2) |
|---|
| 59 | | - return -ENODEV; |
|---|
| 73 | + struct acpi_table_tpm2 *tbl; |
|---|
| 74 | + struct acpi_tpm2_phy *tpm2_phy; |
|---|
| 75 | + int format; |
|---|
| 76 | + int ret; |
|---|
| 60 | 77 | |
|---|
| 61 | 78 | log = &chip->log; |
|---|
| 62 | 79 | |
|---|
| .. | .. |
|---|
| 66 | 83 | if (!chip->acpi_dev_handle) |
|---|
| 67 | 84 | return -ENODEV; |
|---|
| 68 | 85 | |
|---|
| 69 | | - /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ |
|---|
| 70 | | - status = acpi_get_table(ACPI_SIG_TCPA, 1, |
|---|
| 71 | | - (struct acpi_table_header **)&buff); |
|---|
| 86 | + if (chip->flags & TPM_CHIP_FLAG_TPM2) { |
|---|
| 87 | + status = acpi_get_table("TPM2", 1, |
|---|
| 88 | + (struct acpi_table_header **)&tbl); |
|---|
| 89 | + if (ACPI_FAILURE(status)) |
|---|
| 90 | + return -ENODEV; |
|---|
| 72 | 91 | |
|---|
| 73 | | - if (ACPI_FAILURE(status)) |
|---|
| 74 | | - return -ENODEV; |
|---|
| 92 | + if (tbl->header.length < |
|---|
| 93 | + sizeof(*tbl) + sizeof(struct acpi_tpm2_phy)) |
|---|
| 94 | + return -ENODEV; |
|---|
| 75 | 95 | |
|---|
| 76 | | - switch(buff->platform_class) { |
|---|
| 77 | | - case BIOS_SERVER: |
|---|
| 78 | | - len = buff->server.log_max_len; |
|---|
| 79 | | - start = buff->server.log_start_addr; |
|---|
| 80 | | - break; |
|---|
| 81 | | - case BIOS_CLIENT: |
|---|
| 82 | | - default: |
|---|
| 83 | | - len = buff->client.log_max_len; |
|---|
| 84 | | - start = buff->client.log_start_addr; |
|---|
| 85 | | - break; |
|---|
| 96 | + tpm2_phy = (void *)tbl + sizeof(*tbl); |
|---|
| 97 | + len = tpm2_phy->log_area_minimum_length; |
|---|
| 98 | + |
|---|
| 99 | + start = tpm2_phy->log_area_start_address; |
|---|
| 100 | + if (!start || !len) |
|---|
| 101 | + return -ENODEV; |
|---|
| 102 | + |
|---|
| 103 | + format = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; |
|---|
| 104 | + } else { |
|---|
| 105 | + /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ |
|---|
| 106 | + status = acpi_get_table(ACPI_SIG_TCPA, 1, |
|---|
| 107 | + (struct acpi_table_header **)&buff); |
|---|
| 108 | + if (ACPI_FAILURE(status)) |
|---|
| 109 | + return -ENODEV; |
|---|
| 110 | + |
|---|
| 111 | + switch (buff->platform_class) { |
|---|
| 112 | + case BIOS_SERVER: |
|---|
| 113 | + len = buff->server.log_max_len; |
|---|
| 114 | + start = buff->server.log_start_addr; |
|---|
| 115 | + break; |
|---|
| 116 | + case BIOS_CLIENT: |
|---|
| 117 | + default: |
|---|
| 118 | + len = buff->client.log_max_len; |
|---|
| 119 | + start = buff->client.log_start_addr; |
|---|
| 120 | + break; |
|---|
| 121 | + } |
|---|
| 122 | + |
|---|
| 123 | + format = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; |
|---|
| 86 | 124 | } |
|---|
| 87 | 125 | if (!len) { |
|---|
| 88 | 126 | dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__); |
|---|
| .. | .. |
|---|
| 96 | 134 | |
|---|
| 97 | 135 | log->bios_event_log_end = log->bios_event_log + len; |
|---|
| 98 | 136 | |
|---|
| 137 | + ret = -EIO; |
|---|
| 99 | 138 | virt = acpi_os_map_iomem(start, len); |
|---|
| 100 | 139 | if (!virt) |
|---|
| 101 | 140 | goto err; |
|---|
| .. | .. |
|---|
| 103 | 142 | memcpy_fromio(log->bios_event_log, virt, len); |
|---|
| 104 | 143 | |
|---|
| 105 | 144 | acpi_os_unmap_iomem(virt, len); |
|---|
| 106 | | - return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; |
|---|
| 145 | + |
|---|
| 146 | + if (chip->flags & TPM_CHIP_FLAG_TPM2 && |
|---|
| 147 | + !tpm_is_tpm2_log(log->bios_event_log, len)) { |
|---|
| 148 | + /* try EFI log next */ |
|---|
| 149 | + ret = -ENODEV; |
|---|
| 150 | + goto err; |
|---|
| 151 | + } |
|---|
| 152 | + |
|---|
| 153 | + return format; |
|---|
| 107 | 154 | |
|---|
| 108 | 155 | err: |
|---|
| 109 | 156 | kfree(log->bios_event_log); |
|---|
| 110 | 157 | log->bios_event_log = NULL; |
|---|
| 111 | | - return -EIO; |
|---|
| 158 | + return ret; |
|---|
| 112 | 159 | |
|---|
| 113 | 160 | } |
|---|