aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJarkko Sakkinen <jarkko.sakkinen@linux.intel.com>2014-12-12 14:46:38 -0500
committerPeter Huewe <peterhuewe@gmx.de>2015-01-17 08:00:11 -0500
commit7a1d7e6dd76a2070e2d86826391468edc33bb6d6 (patch)
tree11faf31b48a14e1b6d07c0494458ccd5d1f79994
parent313d21eeab9282e01fdcecd40e9ca87e0953627f (diff)
tpm: TPM 2.0 baseline support
TPM 2.0 devices are separated by adding a field 'flags' to struct tpm_chip and defining a flag TPM_CHIP_FLAG_TPM2 for tagging them. This patch adds the following internal functions: - tpm2_get_random() - tpm2_get_tpm_pt() - tpm2_pcr_extend() - tpm2_pcr_read() - tpm2_startup() Additionally, the following exported functions are implemented for implementing TPM 2.0 device drivers: - tpm2_do_selftest() - tpm2_calc_ordinal_durations() - tpm2_gen_interrupt() The existing functions that are exported for the use for existing subsystems have been changed to check the flags field in struct tpm_chip and use appropriate TPM 2.0 counterpart if TPM_CHIP_FLAG_TPM2 is est. The code for tpm2_calc_ordinal_duration() and tpm2_startup() were originally written by Will Arthur. Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> Signed-off-by: Will Arthur <will.c.arthur@intel.com> Reviewed-by: Jasob Gunthorpe <jason.gunthorpe@obsidianresearch.com> Reviewed-by: Stefan Berger <stefanb@linux.vnet.ibm.com> Reviewed-by: Peter Huewe <peterhuewe@gmx.de> Tested-by: Peter Huewe <peterhuewe@gmx.de> [phuewe: Fixed copy paste error * 2] Signed-off-by: Peter Huewe <peterhuewe@gmx.de>
-rw-r--r--drivers/char/tpm/Makefile2
-rw-r--r--drivers/char/tpm/tpm-chip.c27
-rw-r--r--drivers/char/tpm/tpm-interface.c23
-rw-r--r--drivers/char/tpm/tpm.h66
-rw-r--r--drivers/char/tpm/tpm2-cmd.c617
5 files changed, 721 insertions, 14 deletions
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index c715596acb7c..88848edb081c 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -2,7 +2,7 @@
2# Makefile for the kernel tpm device drivers. 2# Makefile for the kernel tpm device drivers.
3# 3#
4obj-$(CONFIG_TCG_TPM) += tpm.o 4obj-$(CONFIG_TCG_TPM) += tpm.o
5tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o 5tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
6tpm-$(CONFIG_ACPI) += tpm_ppi.o 6tpm-$(CONFIG_ACPI) += tpm_ppi.o
7 7
8ifdef CONFIG_ACPI 8ifdef CONFIG_ACPI
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
index 7596eef3bff9..6459af7c1646 100644
--- a/drivers/char/tpm/tpm-chip.c
+++ b/drivers/char/tpm/tpm-chip.c
@@ -195,15 +195,18 @@ int tpm_chip_register(struct tpm_chip *chip)
195 if (rc) 195 if (rc)
196 return rc; 196 return rc;
197 197
198 rc = tpm_sysfs_add_device(chip); 198 /* Populate sysfs for TPM1 devices. */
199 if (rc) 199 if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
200 goto del_misc; 200 rc = tpm_sysfs_add_device(chip);
201 if (rc)
202 goto del_misc;
201 203
202 rc = tpm_add_ppi(chip); 204 rc = tpm_add_ppi(chip);
203 if (rc) 205 if (rc)
204 goto del_sysfs; 206 goto del_sysfs;
205 207
206 chip->bios_dir = tpm_bios_log_setup(chip->devname); 208 chip->bios_dir = tpm_bios_log_setup(chip->devname);
209 }
207 210
208 /* Make the chip available. */ 211 /* Make the chip available. */
209 spin_lock(&driver_lock); 212 spin_lock(&driver_lock);
@@ -241,10 +244,12 @@ void tpm_chip_unregister(struct tpm_chip *chip)
241 spin_unlock(&driver_lock); 244 spin_unlock(&driver_lock);
242 synchronize_rcu(); 245 synchronize_rcu();
243 246
244 if (chip->bios_dir) 247 if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
245 tpm_bios_log_teardown(chip->bios_dir); 248 if (chip->bios_dir)
246 tpm_remove_ppi(chip); 249 tpm_bios_log_teardown(chip->bios_dir);
247 tpm_sysfs_del_device(chip); 250 tpm_remove_ppi(chip);
251 tpm_sysfs_del_device(chip);
252 }
248 253
249 tpm_dev_del_device(chip); 254 tpm_dev_del_device(chip);
250} 255}
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index b6f6b17392fd..20cf94d31386 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -360,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
360 if (chip->vendor.irq) 360 if (chip->vendor.irq)
361 goto out_recv; 361 goto out_recv;
362 362
363 stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); 363 if (chip->flags & TPM_CHIP_FLAG_TPM2)
364 stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
365 else
366 stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
364 do { 367 do {
365 u8 status = chip->ops->status(chip); 368 u8 status = chip->ops->status(chip);
366 if ((status & chip->ops->req_complete_mask) == 369 if ((status & chip->ops->req_complete_mask) ==
@@ -484,6 +487,7 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
484{ 487{
485 struct tpm_cmd_t start_cmd; 488 struct tpm_cmd_t start_cmd;
486 start_cmd.header.in = tpm_startup_header; 489 start_cmd.header.in = tpm_startup_header;
490
487 start_cmd.params.startup_in.startup_type = startup_type; 491 start_cmd.params.startup_in.startup_type = startup_type;
488 return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE, 492 return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
489 "attempting to start the TPM"); 493 "attempting to start the TPM");
@@ -680,7 +684,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
680 chip = tpm_chip_find_get(chip_num); 684 chip = tpm_chip_find_get(chip_num);
681 if (chip == NULL) 685 if (chip == NULL)
682 return -ENODEV; 686 return -ENODEV;
683 rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf); 687 if (chip->flags & TPM_CHIP_FLAG_TPM2)
688 rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
689 else
690 rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
684 tpm_chip_put(chip); 691 tpm_chip_put(chip);
685 return rc; 692 return rc;
686} 693}
@@ -714,6 +721,12 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
714 if (chip == NULL) 721 if (chip == NULL)
715 return -ENODEV; 722 return -ENODEV;
716 723
724 if (chip->flags & TPM_CHIP_FLAG_TPM2) {
725 rc = tpm2_pcr_extend(chip, pcr_idx, hash);
726 tpm_chip_put(chip);
727 return rc;
728 }
729
717 cmd.header.in = pcrextend_header; 730 cmd.header.in = pcrextend_header;
718 cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx); 731 cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
719 memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE); 732 memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
@@ -974,6 +987,12 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
974 if (chip == NULL) 987 if (chip == NULL)
975 return -ENODEV; 988 return -ENODEV;
976 989
990 if (chip->flags & TPM_CHIP_FLAG_TPM2) {
991 err = tpm2_get_random(chip, out, max);
992 tpm_chip_put(chip);
993 return err;
994 }
995
977 do { 996 do {
978 tpm_cmd.header.in = tpm_getrandom_header; 997 tpm_cmd.header.in = tpm_getrandom_header;
979 tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes); 998 tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index d46765b4c97e..cc421cfde389 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -62,6 +62,59 @@ enum tpm_duration {
62#define TPM_ERR_INVALID_POSTINIT 38 62#define TPM_ERR_INVALID_POSTINIT 38
63 63
64#define TPM_HEADER_SIZE 10 64#define TPM_HEADER_SIZE 10
65
66enum tpm2_const {
67 TPM2_PLATFORM_PCR = 24,
68 TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
69 TPM2_TIMEOUT_A = 750,
70 TPM2_TIMEOUT_B = 2000,
71 TPM2_TIMEOUT_C = 200,
72 TPM2_TIMEOUT_D = 30,
73 TPM2_DURATION_SHORT = 20,
74 TPM2_DURATION_MEDIUM = 750,
75 TPM2_DURATION_LONG = 2000,
76};
77
78enum tpm2_structures {
79 TPM2_ST_NO_SESSIONS = 0x8001,
80 TPM2_ST_SESSIONS = 0x8002,
81};
82
83enum tpm2_return_codes {
84 TPM2_RC_INITIALIZE = 0x0100,
85 TPM2_RC_TESTING = 0x090A,
86 TPM2_RC_DISABLED = 0x0120,
87};
88
89enum tpm2_algorithms {
90 TPM2_ALG_SHA1 = 0x0004,
91};
92
93enum tpm2_command_codes {
94 TPM2_CC_FIRST = 0x011F,
95 TPM2_CC_SELF_TEST = 0x0143,
96 TPM2_CC_STARTUP = 0x0144,
97 TPM2_CC_SHUTDOWN = 0x0145,
98 TPM2_CC_GET_CAPABILITY = 0x017A,
99 TPM2_CC_GET_RANDOM = 0x017B,
100 TPM2_CC_PCR_READ = 0x017E,
101 TPM2_CC_PCR_EXTEND = 0x0182,
102 TPM2_CC_LAST = 0x018F,
103};
104
105enum tpm2_permanent_handles {
106 TPM2_RS_PW = 0x40000009,
107};
108
109enum tpm2_capabilities {
110 TPM2_CAP_TPM_PROPERTIES = 6,
111};
112
113enum tpm2_startup_types {
114 TPM2_SU_CLEAR = 0x0000,
115 TPM2_SU_STATE = 0x0001,
116};
117
65struct tpm_chip; 118struct tpm_chip;
66 119
67struct tpm_vendor_specific { 120struct tpm_vendor_specific {
@@ -99,6 +152,7 @@ struct tpm_vendor_specific {
99enum tpm_chip_flags { 152enum tpm_chip_flags {
100 TPM_CHIP_FLAG_REGISTERED = BIT(0), 153 TPM_CHIP_FLAG_REGISTERED = BIT(0),
101 TPM_CHIP_FLAG_PPI = BIT(1), 154 TPM_CHIP_FLAG_PPI = BIT(1),
155 TPM_CHIP_FLAG_TPM2 = BIT(2),
102}; 156};
103 157
104struct tpm_chip { 158struct tpm_chip {
@@ -370,3 +424,15 @@ static inline void tpm_remove_ppi(struct tpm_chip *chip)
370{ 424{
371} 425}
372#endif 426#endif
427
428int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
429int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
430int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
431ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
432 u32 *value, const char *desc);
433
434extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type);
435extern int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
436extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32);
437extern int tpm2_do_selftest(struct tpm_chip *chip);
438extern int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
new file mode 100644
index 000000000000..1abe6502219f
--- /dev/null
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -0,0 +1,617 @@
1/*
2 * Copyright (C) 2014 Intel Corporation
3 *
4 * Authors:
5 * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
6 *
7 * Maintained by: <tpmdd-devel@lists.sourceforge.net>
8 *
9 * This file contains TPM2 protocol implementations of the commands
10 * used by the kernel internally.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; version 2
15 * of the License.
16 */
17
18#include "tpm.h"
19
20struct tpm2_startup_in {
21 __be16 startup_type;
22} __packed;
23
24struct tpm2_self_test_in {
25 u8 full_test;
26} __packed;
27
28struct tpm2_pcr_read_in {
29 __be32 pcr_selects_cnt;
30 __be16 hash_alg;
31 u8 pcr_select_size;
32 u8 pcr_select[TPM2_PCR_SELECT_MIN];
33} __packed;
34
35struct tpm2_pcr_read_out {
36 __be32 update_cnt;
37 __be32 pcr_selects_cnt;
38 __be16 hash_alg;
39 u8 pcr_select_size;
40 u8 pcr_select[TPM2_PCR_SELECT_MIN];
41 __be32 digests_cnt;
42 __be16 digest_size;
43 u8 digest[TPM_DIGEST_SIZE];
44} __packed;
45
46struct tpm2_null_auth_area {
47 __be32 handle;
48 __be16 nonce_size;
49 u8 attributes;
50 __be16 auth_size;
51} __packed;
52
53struct tpm2_pcr_extend_in {
54 __be32 pcr_idx;
55 __be32 auth_area_size;
56 struct tpm2_null_auth_area auth_area;
57 __be32 digest_cnt;
58 __be16 hash_alg;
59 u8 digest[TPM_DIGEST_SIZE];
60} __packed;
61
62struct tpm2_get_tpm_pt_in {
63 __be32 cap_id;
64 __be32 property_id;
65 __be32 property_cnt;
66} __packed;
67
68struct tpm2_get_tpm_pt_out {
69 u8 more_data;
70 __be32 subcap_id;
71 __be32 property_cnt;
72 __be32 property_id;
73 __be32 value;
74} __packed;
75
76struct tpm2_get_random_in {
77 __be16 size;
78} __packed;
79
80struct tpm2_get_random_out {
81 __be16 size;
82 u8 buffer[TPM_MAX_RNG_DATA];
83} __packed;
84
85union tpm2_cmd_params {
86 struct tpm2_startup_in startup_in;
87 struct tpm2_self_test_in selftest_in;
88 struct tpm2_pcr_read_in pcrread_in;
89 struct tpm2_pcr_read_out pcrread_out;
90 struct tpm2_pcr_extend_in pcrextend_in;
91 struct tpm2_get_tpm_pt_in get_tpm_pt_in;
92 struct tpm2_get_tpm_pt_out get_tpm_pt_out;
93 struct tpm2_get_random_in getrandom_in;
94 struct tpm2_get_random_out getrandom_out;
95};
96
97struct tpm2_cmd {
98 tpm_cmd_header header;
99 union tpm2_cmd_params params;
100} __packed;
101
102/*
103 * Array with one entry per ordinal defining the maximum amount
104 * of time the chip could take to return the result. The values
105 * of the SHORT, MEDIUM, and LONG durations are taken from the
106 * PC Client Profile (PTP) specification.
107 */
108static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = {
109 TPM_UNDEFINED, /* 11F */
110 TPM_UNDEFINED, /* 120 */
111 TPM_LONG, /* 121 */
112 TPM_UNDEFINED, /* 122 */
113 TPM_UNDEFINED, /* 123 */
114 TPM_UNDEFINED, /* 124 */
115 TPM_UNDEFINED, /* 125 */
116 TPM_UNDEFINED, /* 126 */
117 TPM_UNDEFINED, /* 127 */
118 TPM_UNDEFINED, /* 128 */
119 TPM_LONG, /* 129 */
120 TPM_UNDEFINED, /* 12a */
121 TPM_UNDEFINED, /* 12b */
122 TPM_UNDEFINED, /* 12c */
123 TPM_UNDEFINED, /* 12d */
124 TPM_UNDEFINED, /* 12e */
125 TPM_UNDEFINED, /* 12f */
126 TPM_UNDEFINED, /* 130 */
127 TPM_UNDEFINED, /* 131 */
128 TPM_UNDEFINED, /* 132 */
129 TPM_UNDEFINED, /* 133 */
130 TPM_UNDEFINED, /* 134 */
131 TPM_UNDEFINED, /* 135 */
132 TPM_UNDEFINED, /* 136 */
133 TPM_UNDEFINED, /* 137 */
134 TPM_UNDEFINED, /* 138 */
135 TPM_UNDEFINED, /* 139 */
136 TPM_UNDEFINED, /* 13a */
137 TPM_UNDEFINED, /* 13b */
138 TPM_UNDEFINED, /* 13c */
139 TPM_UNDEFINED, /* 13d */
140 TPM_MEDIUM, /* 13e */
141 TPM_UNDEFINED, /* 13f */
142 TPM_UNDEFINED, /* 140 */
143 TPM_UNDEFINED, /* 141 */
144 TPM_UNDEFINED, /* 142 */
145 TPM_LONG, /* 143 */
146 TPM_MEDIUM, /* 144 */
147 TPM_UNDEFINED, /* 145 */
148 TPM_UNDEFINED, /* 146 */
149 TPM_UNDEFINED, /* 147 */
150 TPM_UNDEFINED, /* 148 */
151 TPM_UNDEFINED, /* 149 */
152 TPM_UNDEFINED, /* 14a */
153 TPM_UNDEFINED, /* 14b */
154 TPM_UNDEFINED, /* 14c */
155 TPM_UNDEFINED, /* 14d */
156 TPM_LONG, /* 14e */
157 TPM_UNDEFINED, /* 14f */
158 TPM_UNDEFINED, /* 150 */
159 TPM_UNDEFINED, /* 151 */
160 TPM_UNDEFINED, /* 152 */
161 TPM_UNDEFINED, /* 153 */
162 TPM_UNDEFINED, /* 154 */
163 TPM_UNDEFINED, /* 155 */
164 TPM_UNDEFINED, /* 156 */
165 TPM_UNDEFINED, /* 157 */
166 TPM_UNDEFINED, /* 158 */
167 TPM_UNDEFINED, /* 159 */
168 TPM_UNDEFINED, /* 15a */
169 TPM_UNDEFINED, /* 15b */
170 TPM_MEDIUM, /* 15c */
171 TPM_UNDEFINED, /* 15d */
172 TPM_UNDEFINED, /* 15e */
173 TPM_UNDEFINED, /* 15f */
174 TPM_UNDEFINED, /* 160 */
175 TPM_UNDEFINED, /* 161 */
176 TPM_UNDEFINED, /* 162 */
177 TPM_UNDEFINED, /* 163 */
178 TPM_UNDEFINED, /* 164 */
179 TPM_UNDEFINED, /* 165 */
180 TPM_UNDEFINED, /* 166 */
181 TPM_UNDEFINED, /* 167 */
182 TPM_UNDEFINED, /* 168 */
183 TPM_UNDEFINED, /* 169 */
184 TPM_UNDEFINED, /* 16a */
185 TPM_UNDEFINED, /* 16b */
186 TPM_UNDEFINED, /* 16c */
187 TPM_UNDEFINED, /* 16d */
188 TPM_UNDEFINED, /* 16e */
189 TPM_UNDEFINED, /* 16f */
190 TPM_UNDEFINED, /* 170 */
191 TPM_UNDEFINED, /* 171 */
192 TPM_UNDEFINED, /* 172 */
193 TPM_UNDEFINED, /* 173 */
194 TPM_UNDEFINED, /* 174 */
195 TPM_UNDEFINED, /* 175 */
196 TPM_UNDEFINED, /* 176 */
197 TPM_LONG, /* 177 */
198 TPM_UNDEFINED, /* 178 */
199 TPM_UNDEFINED, /* 179 */
200 TPM_MEDIUM, /* 17a */
201 TPM_LONG, /* 17b */
202 TPM_UNDEFINED, /* 17c */
203 TPM_UNDEFINED, /* 17d */
204 TPM_UNDEFINED, /* 17e */
205 TPM_UNDEFINED, /* 17f */
206 TPM_UNDEFINED, /* 180 */
207 TPM_UNDEFINED, /* 181 */
208 TPM_MEDIUM, /* 182 */
209 TPM_UNDEFINED, /* 183 */
210 TPM_UNDEFINED, /* 184 */
211 TPM_MEDIUM, /* 185 */
212 TPM_MEDIUM, /* 186 */
213 TPM_UNDEFINED, /* 187 */
214 TPM_UNDEFINED, /* 188 */
215 TPM_UNDEFINED, /* 189 */
216 TPM_UNDEFINED, /* 18a */
217 TPM_UNDEFINED, /* 18b */
218 TPM_UNDEFINED, /* 18c */
219 TPM_UNDEFINED, /* 18d */
220 TPM_UNDEFINED, /* 18e */
221 TPM_UNDEFINED /* 18f */
222};
223
224#define TPM2_PCR_READ_IN_SIZE \
225 (sizeof(struct tpm_input_header) + \
226 sizeof(struct tpm2_pcr_read_in))
227
228static const struct tpm_input_header tpm2_pcrread_header = {
229 .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
230 .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE),
231 .ordinal = cpu_to_be32(TPM2_CC_PCR_READ)
232};
233
234/**
235 * tpm2_pcr_read() - read a PCR value
236 * @chip: TPM chip to use.
237 * @pcr_idx: index of the PCR to read.
238 * @ref_buf: buffer to store the resulting hash,
239 *
240 * 0 is returned when the operation is successful. If a negative number is
241 * returned it remarks a POSIX error code. If a positive number is returned
242 * it remarks a TPM error.
243 */
244int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
245{
246 int rc;
247 struct tpm2_cmd cmd;
248 u8 *buf;
249
250 if (pcr_idx >= TPM2_PLATFORM_PCR)
251 return -EINVAL;
252
253 cmd.header.in = tpm2_pcrread_header;
254 cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1);
255 cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
256 cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN;
257
258 memset(cmd.params.pcrread_in.pcr_select, 0,
259 sizeof(cmd.params.pcrread_in.pcr_select));
260 cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
261
262 rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
263 "attempting to read a pcr value");
264 if (rc == 0) {
265 buf = cmd.params.pcrread_out.digest;
266 memcpy(res_buf, buf, TPM_DIGEST_SIZE);
267 }
268
269 return rc;
270}
271
272#define TPM2_GET_PCREXTEND_IN_SIZE \
273 (sizeof(struct tpm_input_header) + \
274 sizeof(struct tpm2_pcr_extend_in))
275
276static const struct tpm_input_header tpm2_pcrextend_header = {
277 .tag = cpu_to_be16(TPM2_ST_SESSIONS),
278 .length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE),
279 .ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND)
280};
281
282/**
283 * tpm2_pcr_extend() - extend a PCR value
284 * @chip: TPM chip to use.
285 * @pcr_idx: index of the PCR.
286 * @hash: hash value to use for the extend operation.
287 *
288 * 0 is returned when the operation is successful. If a negative number is
289 * returned it remarks a POSIX error code. If a positive number is returned
290 * it remarks a TPM error.
291 */
292int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
293{
294 struct tpm2_cmd cmd;
295 int rc;
296
297 cmd.header.in = tpm2_pcrextend_header;
298 cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
299 cmd.params.pcrextend_in.auth_area_size =
300 cpu_to_be32(sizeof(struct tpm2_null_auth_area));
301 cmd.params.pcrextend_in.auth_area.handle =
302 cpu_to_be32(TPM2_RS_PW);
303 cmd.params.pcrextend_in.auth_area.nonce_size = 0;
304 cmd.params.pcrextend_in.auth_area.attributes = 0;
305 cmd.params.pcrextend_in.auth_area.auth_size = 0;
306 cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1);
307 cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
308 memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE);
309
310 rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
311 "attempting extend a PCR value");
312
313 return rc;
314}
315
316#define TPM2_GETRANDOM_IN_SIZE \
317 (sizeof(struct tpm_input_header) + \
318 sizeof(struct tpm2_get_random_in))
319
320static const struct tpm_input_header tpm2_getrandom_header = {
321 .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
322 .length = cpu_to_be32(TPM2_GETRANDOM_IN_SIZE),
323 .ordinal = cpu_to_be32(TPM2_CC_GET_RANDOM)
324};
325
326/**
327 * tpm2_get_random() - get random bytes from the TPM RNG
328 * @chip: TPM chip to use
329 * @out: destination buffer for the random bytes
330 * @max: the max number of bytes to write to @out
331 *
332 * 0 is returned when the operation is successful. If a negative number is
333 * returned it remarks a POSIX error code. If a positive number is returned
334 * it remarks a TPM error.
335 */
336int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
337{
338 struct tpm2_cmd cmd;
339 u32 recd;
340 u32 num_bytes;
341 int err;
342 int total = 0;
343 int retries = 5;
344 u8 *dest = out;
345
346 num_bytes = min_t(u32, max, sizeof(cmd.params.getrandom_out.buffer));
347
348 if (!out || !num_bytes ||
349 max > sizeof(cmd.params.getrandom_out.buffer))
350 return -EINVAL;
351
352 do {
353 cmd.header.in = tpm2_getrandom_header;
354 cmd.params.getrandom_in.size = cpu_to_be16(num_bytes);
355
356 err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
357 "attempting get random");
358 if (err)
359 break;
360
361 recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size),
362 num_bytes);
363 memcpy(dest, cmd.params.getrandom_out.buffer, recd);
364
365 dest += recd;
366 total += recd;
367 num_bytes -= recd;
368 } while (retries-- && total < max);
369
370 return total ? total : -EIO;
371}
372
373#define TPM2_GET_TPM_PT_IN_SIZE \
374 (sizeof(struct tpm_input_header) + \
375 sizeof(struct tpm2_get_tpm_pt_in))
376
377static const struct tpm_input_header tpm2_get_tpm_pt_header = {
378 .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
379 .length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE),
380 .ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY)
381};
382
383/**
384 * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property
385 * @chip: TPM chip to use.
386 * @property_id: property ID.
387 * @value: output variable.
388 * @desc: passed to tpm_transmit_cmd()
389 *
390 * 0 is returned when the operation is successful. If a negative number is
391 * returned it remarks a POSIX error code. If a positive number is returned
392 * it remarks a TPM error.
393 */
394ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
395 const char *desc)
396{
397 struct tpm2_cmd cmd;
398 int rc;
399
400 cmd.header.in = tpm2_get_tpm_pt_header;
401 cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES);
402 cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id);
403 cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
404
405 rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), desc);
406 if (!rc)
407 *value = cmd.params.get_tpm_pt_out.value;
408
409 return rc;
410}
411
412#define TPM2_STARTUP_IN_SIZE \
413 (sizeof(struct tpm_input_header) + \
414 sizeof(struct tpm2_startup_in))
415
416static const struct tpm_input_header tpm2_startup_header = {
417 .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
418 .length = cpu_to_be32(TPM2_STARTUP_IN_SIZE),
419 .ordinal = cpu_to_be32(TPM2_CC_STARTUP)
420};
421
422/**
423 * tpm2_startup() - send startup command to the TPM chip
424 * @chip: TPM chip to use.
425 * @startup_type startup type. The value is either
426 * TPM_SU_CLEAR or TPM_SU_STATE.
427 *
428 * 0 is returned when the operation is successful. If a negative number is
429 * returned it remarks a POSIX error code. If a positive number is returned
430 * it remarks a TPM error.
431 */
432int tpm2_startup(struct tpm_chip *chip, u16 startup_type)
433{
434 struct tpm2_cmd cmd;
435
436 cmd.header.in = tpm2_startup_header;
437
438 cmd.params.startup_in.startup_type = cpu_to_be16(startup_type);
439 return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
440 "attempting to start the TPM");
441}
442EXPORT_SYMBOL_GPL(tpm2_startup);
443
444#define TPM2_SHUTDOWN_IN_SIZE \
445 (sizeof(struct tpm_input_header) + \
446 sizeof(struct tpm2_startup_in))
447
448static const struct tpm_input_header tpm2_shutdown_header = {
449 .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
450 .length = cpu_to_be32(TPM2_SHUTDOWN_IN_SIZE),
451 .ordinal = cpu_to_be32(TPM2_CC_SHUTDOWN)
452};
453
454/**
455 * tpm2_shutdown() - send shutdown command to the TPM chip
456 * @chip: TPM chip to use.
457 * @shutdown_type shutdown type. The value is either
458 * TPM_SU_CLEAR or TPM_SU_STATE.
459 *
460 * 0 is returned when the operation is successful. If a negative number is
461 * returned it remarks a POSIX error code. If a positive number is returned
462 * it remarks a TPM error.
463 */
464int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
465{
466 struct tpm2_cmd cmd;
467
468 cmd.header.in = tpm2_shutdown_header;
469
470 cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
471 return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
472 "stopping the TPM");
473}
474EXPORT_SYMBOL_GPL(tpm2_shutdown);
475
476/*
477 * tpm2_calc_ordinal_duration() - maximum duration for a command
478 * @chip: TPM chip to use.
479 * @ordinal: command code number.
480 *
481 * 0 is returned when the operation is successful. If a negative number is
482 * returned it remarks a POSIX error code. If a positive number is returned
483 * it remarks a TPM error.
484 */
485unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
486{
487 int index = TPM_UNDEFINED;
488 int duration = 0;
489
490 if (ordinal >= TPM2_CC_FIRST && ordinal <= TPM2_CC_LAST)
491 index = tpm2_ordinal_duration[ordinal - TPM2_CC_FIRST];
492
493 if (index != TPM_UNDEFINED)
494 duration = chip->vendor.duration[index];
495
496 if (duration <= 0)
497 duration = 2 * 60 * HZ;
498
499 return duration;
500}
501EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration);
502
503#define TPM2_SELF_TEST_IN_SIZE \
504 (sizeof(struct tpm_input_header) + \
505 sizeof(struct tpm2_self_test_in))
506
507static const struct tpm_input_header tpm2_selftest_header = {
508 .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
509 .length = cpu_to_be32(TPM2_SELF_TEST_IN_SIZE),
510 .ordinal = cpu_to_be32(TPM2_CC_SELF_TEST)
511};
512
513/**
514 * tpm2_continue_selftest() - start a self test
515 * @chip: TPM chip to use
516 * @full: test all commands instead of testing only those that were not
517 * previously tested.
518 *
519 * 0 is returned when the operation is successful. If a negative number is
520 * returned it remarks a POSIX error code. If a positive number is returned
521 * it remarks a TPM error.
522 */
523static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
524{
525 int rc;
526 struct tpm2_cmd cmd;
527
528 cmd.header.in = tpm2_selftest_header;
529 cmd.params.selftest_in.full_test = full;
530
531 rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE,
532 "continue selftest");
533
534 /* At least some prototype chips seem to give RC_TESTING error
535 * immediately. This is a workaround for that.
536 */
537 if (rc == TPM2_RC_TESTING) {
538 dev_warn(chip->pdev, "Got RC_TESTING, ignoring\n");
539 rc = 0;
540 }
541
542 return rc;
543}
544
545/**
546 * tpm2_do_selftest() - run a full self test
547 * @chip: TPM chip to use
548 *
549 * During the self test TPM2 commands return with the error code RC_TESTING.
550 * Waiting is done by issuing PCR read until it executes successfully.
551 *
552 * 0 is returned when the operation is successful. If a negative number is
553 * returned it remarks a POSIX error code. If a positive number is returned
554 * it remarks a TPM error.
555 */
556int tpm2_do_selftest(struct tpm_chip *chip)
557{
558 int rc;
559 unsigned int loops;
560 unsigned int delay_msec = 100;
561 unsigned long duration;
562 struct tpm2_cmd cmd;
563 int i;
564
565 duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST);
566
567 loops = jiffies_to_msecs(duration) / delay_msec;
568
569 rc = tpm2_start_selftest(chip, true);
570 if (rc)
571 return rc;
572
573 for (i = 0; i < loops; i++) {
574 /* Attempt to read a PCR value */
575 cmd.header.in = tpm2_pcrread_header;
576 cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1);
577 cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
578 cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN;
579 cmd.params.pcrread_in.pcr_select[0] = 0x01;
580 cmd.params.pcrread_in.pcr_select[1] = 0x00;
581 cmd.params.pcrread_in.pcr_select[2] = 0x00;
582
583 rc = tpm_transmit_cmd(chip, (u8 *) &cmd, sizeof(cmd), NULL);
584 if (rc < 0)
585 break;
586
587 rc = be32_to_cpu(cmd.header.out.return_code);
588 if (rc != TPM2_RC_TESTING)
589 break;
590
591 msleep(delay_msec);
592 }
593
594 return rc;
595}
596EXPORT_SYMBOL_GPL(tpm2_do_selftest);
597
598/**
599 * tpm2_gen_interrupt() - generate an interrupt
600 * @chip: TPM chip to use
601 * @quiet: surpress the error message
602 *
603 * 0 is returned when the operation is successful. If a negative number is
604 * returned it remarks a POSIX error code. If a positive number is returned
605 * it remarks a TPM error.
606 */
607int tpm2_gen_interrupt(struct tpm_chip *chip, bool quiet)
608{
609 const char *desc = NULL;
610 u32 dummy;
611
612 if (!quiet)
613 desc = "attempting to generate an interrupt";
614
615 return tpm2_get_tpm_pt(chip, TPM2_CAP_TPM_PROPERTIES, &dummy, desc);
616}
617EXPORT_SYMBOL_GPL(tpm2_gen_interrupt);