diff options
author | Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com> | 2014-12-12 14:46:38 -0500 |
---|---|---|
committer | Peter Huewe <peterhuewe@gmx.de> | 2015-01-17 08:00:11 -0500 |
commit | 7a1d7e6dd76a2070e2d86826391468edc33bb6d6 (patch) | |
tree | 11faf31b48a14e1b6d07c0494458ccd5d1f79994 | |
parent | 313d21eeab9282e01fdcecd40e9ca87e0953627f (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/Makefile | 2 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-chip.c | 27 | ||||
-rw-r--r-- | drivers/char/tpm/tpm-interface.c | 23 | ||||
-rw-r--r-- | drivers/char/tpm/tpm.h | 66 | ||||
-rw-r--r-- | drivers/char/tpm/tpm2-cmd.c | 617 |
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 | # |
4 | obj-$(CONFIG_TCG_TPM) += tpm.o | 4 | obj-$(CONFIG_TCG_TPM) += tpm.o |
5 | tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o | 5 | tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o |
6 | tpm-$(CONFIG_ACPI) += tpm_ppi.o | 6 | tpm-$(CONFIG_ACPI) += tpm_ppi.o |
7 | 7 | ||
8 | ifdef CONFIG_ACPI | 8 | ifdef 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 | |||
66 | enum 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 | |||
78 | enum tpm2_structures { | ||
79 | TPM2_ST_NO_SESSIONS = 0x8001, | ||
80 | TPM2_ST_SESSIONS = 0x8002, | ||
81 | }; | ||
82 | |||
83 | enum tpm2_return_codes { | ||
84 | TPM2_RC_INITIALIZE = 0x0100, | ||
85 | TPM2_RC_TESTING = 0x090A, | ||
86 | TPM2_RC_DISABLED = 0x0120, | ||
87 | }; | ||
88 | |||
89 | enum tpm2_algorithms { | ||
90 | TPM2_ALG_SHA1 = 0x0004, | ||
91 | }; | ||
92 | |||
93 | enum 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 | |||
105 | enum tpm2_permanent_handles { | ||
106 | TPM2_RS_PW = 0x40000009, | ||
107 | }; | ||
108 | |||
109 | enum tpm2_capabilities { | ||
110 | TPM2_CAP_TPM_PROPERTIES = 6, | ||
111 | }; | ||
112 | |||
113 | enum tpm2_startup_types { | ||
114 | TPM2_SU_CLEAR = 0x0000, | ||
115 | TPM2_SU_STATE = 0x0001, | ||
116 | }; | ||
117 | |||
65 | struct tpm_chip; | 118 | struct tpm_chip; |
66 | 119 | ||
67 | struct tpm_vendor_specific { | 120 | struct tpm_vendor_specific { |
@@ -99,6 +152,7 @@ struct tpm_vendor_specific { | |||
99 | enum tpm_chip_flags { | 152 | enum 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 | ||
104 | struct tpm_chip { | 158 | struct 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 | |||
428 | int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf); | ||
429 | int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash); | ||
430 | int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max); | ||
431 | ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, | ||
432 | u32 *value, const char *desc); | ||
433 | |||
434 | extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type); | ||
435 | extern int tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type); | ||
436 | extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32); | ||
437 | extern int tpm2_do_selftest(struct tpm_chip *chip); | ||
438 | extern 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 | |||
20 | struct tpm2_startup_in { | ||
21 | __be16 startup_type; | ||
22 | } __packed; | ||
23 | |||
24 | struct tpm2_self_test_in { | ||
25 | u8 full_test; | ||
26 | } __packed; | ||
27 | |||
28 | struct 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 | |||
35 | struct 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 | |||
46 | struct tpm2_null_auth_area { | ||
47 | __be32 handle; | ||
48 | __be16 nonce_size; | ||
49 | u8 attributes; | ||
50 | __be16 auth_size; | ||
51 | } __packed; | ||
52 | |||
53 | struct 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 | |||
62 | struct tpm2_get_tpm_pt_in { | ||
63 | __be32 cap_id; | ||
64 | __be32 property_id; | ||
65 | __be32 property_cnt; | ||
66 | } __packed; | ||
67 | |||
68 | struct 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 | |||
76 | struct tpm2_get_random_in { | ||
77 | __be16 size; | ||
78 | } __packed; | ||
79 | |||
80 | struct tpm2_get_random_out { | ||
81 | __be16 size; | ||
82 | u8 buffer[TPM_MAX_RNG_DATA]; | ||
83 | } __packed; | ||
84 | |||
85 | union 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 | |||
97 | struct 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 | */ | ||
108 | static 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 | |||
228 | static 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 | */ | ||
244 | int 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 | |||
276 | static 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 | */ | ||
292 | int 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 | |||
320 | static 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 | */ | ||
336 | int 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 | |||
377 | static 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 | */ | ||
394 | ssize_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 | |||
416 | static 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 | */ | ||
432 | int 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 | } | ||
442 | EXPORT_SYMBOL_GPL(tpm2_startup); | ||
443 | |||
444 | #define TPM2_SHUTDOWN_IN_SIZE \ | ||
445 | (sizeof(struct tpm_input_header) + \ | ||
446 | sizeof(struct tpm2_startup_in)) | ||
447 | |||
448 | static 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 | */ | ||
464 | int 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 | } | ||
474 | EXPORT_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 | */ | ||
485 | unsigned 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 | } | ||
501 | EXPORT_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 | |||
507 | static 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 | */ | ||
523 | static 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 | */ | ||
556 | int 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 | } | ||
596 | EXPORT_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 | */ | ||
607 | int 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 | } | ||
617 | EXPORT_SYMBOL_GPL(tpm2_gen_interrupt); | ||