.. | .. |
---|
| 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 | + acpi_put_table((struct acpi_table_header *)tbl); |
---|
| 95 | + return -ENODEV; |
---|
| 96 | + } |
---|
75 | 97 | |
---|
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; |
---|
| 98 | + tpm2_phy = (void *)tbl + sizeof(*tbl); |
---|
| 99 | + len = tpm2_phy->log_area_minimum_length; |
---|
| 100 | + |
---|
| 101 | + start = tpm2_phy->log_area_start_address; |
---|
| 102 | + if (!start || !len) { |
---|
| 103 | + acpi_put_table((struct acpi_table_header *)tbl); |
---|
| 104 | + return -ENODEV; |
---|
| 105 | + } |
---|
| 106 | + |
---|
| 107 | + acpi_put_table((struct acpi_table_header *)tbl); |
---|
| 108 | + format = EFI_TCG2_EVENT_LOG_FORMAT_TCG_2; |
---|
| 109 | + } else { |
---|
| 110 | + /* Find TCPA entry in RSDT (ACPI_LOGICAL_ADDRESSING) */ |
---|
| 111 | + status = acpi_get_table(ACPI_SIG_TCPA, 1, |
---|
| 112 | + (struct acpi_table_header **)&buff); |
---|
| 113 | + if (ACPI_FAILURE(status)) |
---|
| 114 | + return -ENODEV; |
---|
| 115 | + |
---|
| 116 | + switch (buff->platform_class) { |
---|
| 117 | + case BIOS_SERVER: |
---|
| 118 | + len = buff->server.log_max_len; |
---|
| 119 | + start = buff->server.log_start_addr; |
---|
| 120 | + break; |
---|
| 121 | + case BIOS_CLIENT: |
---|
| 122 | + default: |
---|
| 123 | + len = buff->client.log_max_len; |
---|
| 124 | + start = buff->client.log_start_addr; |
---|
| 125 | + break; |
---|
| 126 | + } |
---|
| 127 | + |
---|
| 128 | + acpi_put_table((struct acpi_table_header *)buff); |
---|
| 129 | + format = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; |
---|
86 | 130 | } |
---|
| 131 | + |
---|
87 | 132 | if (!len) { |
---|
88 | 133 | dev_warn(&chip->dev, "%s: TCPA log area empty\n", __func__); |
---|
89 | 134 | return -EIO; |
---|
.. | .. |
---|
96 | 141 | |
---|
97 | 142 | log->bios_event_log_end = log->bios_event_log + len; |
---|
98 | 143 | |
---|
| 144 | + ret = -EIO; |
---|
99 | 145 | virt = acpi_os_map_iomem(start, len); |
---|
100 | | - if (!virt) |
---|
| 146 | + if (!virt) { |
---|
| 147 | + dev_warn(&chip->dev, "%s: Failed to map ACPI memory\n", __func__); |
---|
| 148 | + /* try EFI log next */ |
---|
| 149 | + ret = -ENODEV; |
---|
101 | 150 | goto err; |
---|
| 151 | + } |
---|
102 | 152 | |
---|
103 | 153 | memcpy_fromio(log->bios_event_log, virt, len); |
---|
104 | 154 | |
---|
105 | 155 | acpi_os_unmap_iomem(virt, len); |
---|
106 | | - return EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; |
---|
| 156 | + |
---|
| 157 | + if (chip->flags & TPM_CHIP_FLAG_TPM2 && |
---|
| 158 | + !tpm_is_tpm2_log(log->bios_event_log, len)) { |
---|
| 159 | + /* try EFI log next */ |
---|
| 160 | + ret = -ENODEV; |
---|
| 161 | + goto err; |
---|
| 162 | + } |
---|
| 163 | + |
---|
| 164 | + return format; |
---|
107 | 165 | |
---|
108 | 166 | err: |
---|
109 | 167 | kfree(log->bios_event_log); |
---|
110 | 168 | log->bios_event_log = NULL; |
---|
111 | | - return -EIO; |
---|
112 | | - |
---|
| 169 | + return ret; |
---|
113 | 170 | } |
---|