diff options
Diffstat (limited to 'drivers/char/tpm/tpm.c')
-rw-r--r-- | drivers/char/tpm/tpm.c | 312 |
1 files changed, 309 insertions, 3 deletions
diff --git a/drivers/char/tpm/tpm.c b/drivers/char/tpm/tpm.c index 5e58296f2832..e54bcb4e4e3e 100644 --- a/drivers/char/tpm/tpm.c +++ b/drivers/char/tpm/tpm.c | |||
@@ -35,10 +35,290 @@ enum tpm_const { | |||
35 | TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) | 35 | TPM_NUM_MASK_ENTRIES = TPM_NUM_DEVICES / (8 * sizeof(int)) |
36 | }; | 36 | }; |
37 | 37 | ||
38 | enum tpm_duration { | ||
39 | TPM_SHORT = 0, | ||
40 | TPM_MEDIUM = 1, | ||
41 | TPM_LONG = 2, | ||
42 | TPM_UNDEFINED, | ||
43 | }; | ||
44 | |||
45 | #define TPM_MAX_ORDINAL 243 | ||
46 | #define TPM_MAX_PROTECTED_ORDINAL 12 | ||
47 | #define TPM_PROTECTED_ORDINAL_MASK 0xFF | ||
48 | |||
38 | static LIST_HEAD(tpm_chip_list); | 49 | static LIST_HEAD(tpm_chip_list); |
39 | static DEFINE_SPINLOCK(driver_lock); | 50 | static DEFINE_SPINLOCK(driver_lock); |
40 | static int dev_mask[TPM_NUM_MASK_ENTRIES]; | 51 | static int dev_mask[TPM_NUM_MASK_ENTRIES]; |
41 | 52 | ||
53 | /* | ||
54 | * Array with one entry per ordinal defining the maximum amount | ||
55 | * of time the chip could take to return the result. The ordinal | ||
56 | * designation of short, medium or long is defined in a table in | ||
57 | * TCG Specification TPM Main Part 2 TPM Structures Section 17. The | ||
58 | * values of the SHORT, MEDIUM, and LONG durations are retrieved | ||
59 | * from the chip during initialization with a call to tpm_get_timeouts. | ||
60 | */ | ||
61 | static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = { | ||
62 | TPM_UNDEFINED, /* 0 */ | ||
63 | TPM_UNDEFINED, | ||
64 | TPM_UNDEFINED, | ||
65 | TPM_UNDEFINED, | ||
66 | TPM_UNDEFINED, | ||
67 | TPM_UNDEFINED, /* 5 */ | ||
68 | TPM_UNDEFINED, | ||
69 | TPM_UNDEFINED, | ||
70 | TPM_UNDEFINED, | ||
71 | TPM_UNDEFINED, | ||
72 | TPM_SHORT, /* 10 */ | ||
73 | TPM_SHORT, | ||
74 | }; | ||
75 | |||
76 | static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { | ||
77 | TPM_UNDEFINED, /* 0 */ | ||
78 | TPM_UNDEFINED, | ||
79 | TPM_UNDEFINED, | ||
80 | TPM_UNDEFINED, | ||
81 | TPM_UNDEFINED, | ||
82 | TPM_UNDEFINED, /* 5 */ | ||
83 | TPM_UNDEFINED, | ||
84 | TPM_UNDEFINED, | ||
85 | TPM_UNDEFINED, | ||
86 | TPM_UNDEFINED, | ||
87 | TPM_SHORT, /* 10 */ | ||
88 | TPM_SHORT, | ||
89 | TPM_MEDIUM, | ||
90 | TPM_LONG, | ||
91 | TPM_LONG, | ||
92 | TPM_MEDIUM, /* 15 */ | ||
93 | TPM_SHORT, | ||
94 | TPM_SHORT, | ||
95 | TPM_MEDIUM, | ||
96 | TPM_LONG, | ||
97 | TPM_SHORT, /* 20 */ | ||
98 | TPM_SHORT, | ||
99 | TPM_MEDIUM, | ||
100 | TPM_MEDIUM, | ||
101 | TPM_MEDIUM, | ||
102 | TPM_SHORT, /* 25 */ | ||
103 | TPM_SHORT, | ||
104 | TPM_MEDIUM, | ||
105 | TPM_SHORT, | ||
106 | TPM_SHORT, | ||
107 | TPM_MEDIUM, /* 30 */ | ||
108 | TPM_LONG, | ||
109 | TPM_MEDIUM, | ||
110 | TPM_SHORT, | ||
111 | TPM_SHORT, | ||
112 | TPM_SHORT, /* 35 */ | ||
113 | TPM_MEDIUM, | ||
114 | TPM_MEDIUM, | ||
115 | TPM_UNDEFINED, | ||
116 | TPM_UNDEFINED, | ||
117 | TPM_MEDIUM, /* 40 */ | ||
118 | TPM_LONG, | ||
119 | TPM_MEDIUM, | ||
120 | TPM_SHORT, | ||
121 | TPM_SHORT, | ||
122 | TPM_SHORT, /* 45 */ | ||
123 | TPM_SHORT, | ||
124 | TPM_SHORT, | ||
125 | TPM_SHORT, | ||
126 | TPM_LONG, | ||
127 | TPM_MEDIUM, /* 50 */ | ||
128 | TPM_MEDIUM, | ||
129 | TPM_UNDEFINED, | ||
130 | TPM_UNDEFINED, | ||
131 | TPM_UNDEFINED, | ||
132 | TPM_UNDEFINED, /* 55 */ | ||
133 | TPM_UNDEFINED, | ||
134 | TPM_UNDEFINED, | ||
135 | TPM_UNDEFINED, | ||
136 | TPM_UNDEFINED, | ||
137 | TPM_MEDIUM, /* 60 */ | ||
138 | TPM_MEDIUM, | ||
139 | TPM_MEDIUM, | ||
140 | TPM_SHORT, | ||
141 | TPM_SHORT, | ||
142 | TPM_MEDIUM, /* 65 */ | ||
143 | TPM_UNDEFINED, | ||
144 | TPM_UNDEFINED, | ||
145 | TPM_UNDEFINED, | ||
146 | TPM_UNDEFINED, | ||
147 | TPM_SHORT, /* 70 */ | ||
148 | TPM_SHORT, | ||
149 | TPM_UNDEFINED, | ||
150 | TPM_UNDEFINED, | ||
151 | TPM_UNDEFINED, | ||
152 | TPM_UNDEFINED, /* 75 */ | ||
153 | TPM_UNDEFINED, | ||
154 | TPM_UNDEFINED, | ||
155 | TPM_UNDEFINED, | ||
156 | TPM_UNDEFINED, | ||
157 | TPM_LONG, /* 80 */ | ||
158 | TPM_UNDEFINED, | ||
159 | TPM_MEDIUM, | ||
160 | TPM_LONG, | ||
161 | TPM_SHORT, | ||
162 | TPM_UNDEFINED, /* 85 */ | ||
163 | TPM_UNDEFINED, | ||
164 | TPM_UNDEFINED, | ||
165 | TPM_UNDEFINED, | ||
166 | TPM_UNDEFINED, | ||
167 | TPM_SHORT, /* 90 */ | ||
168 | TPM_SHORT, | ||
169 | TPM_SHORT, | ||
170 | TPM_SHORT, | ||
171 | TPM_SHORT, | ||
172 | TPM_UNDEFINED, /* 95 */ | ||
173 | TPM_UNDEFINED, | ||
174 | TPM_UNDEFINED, | ||
175 | TPM_UNDEFINED, | ||
176 | TPM_UNDEFINED, | ||
177 | TPM_MEDIUM, /* 100 */ | ||
178 | TPM_SHORT, | ||
179 | TPM_SHORT, | ||
180 | TPM_UNDEFINED, | ||
181 | TPM_UNDEFINED, | ||
182 | TPM_UNDEFINED, /* 105 */ | ||
183 | TPM_UNDEFINED, | ||
184 | TPM_UNDEFINED, | ||
185 | TPM_UNDEFINED, | ||
186 | TPM_UNDEFINED, | ||
187 | TPM_SHORT, /* 110 */ | ||
188 | TPM_SHORT, | ||
189 | TPM_SHORT, | ||
190 | TPM_SHORT, | ||
191 | TPM_SHORT, | ||
192 | TPM_SHORT, /* 115 */ | ||
193 | TPM_SHORT, | ||
194 | TPM_SHORT, | ||
195 | TPM_UNDEFINED, | ||
196 | TPM_UNDEFINED, | ||
197 | TPM_LONG, /* 120 */ | ||
198 | TPM_LONG, | ||
199 | TPM_MEDIUM, | ||
200 | TPM_UNDEFINED, | ||
201 | TPM_SHORT, | ||
202 | TPM_SHORT, /* 125 */ | ||
203 | TPM_SHORT, | ||
204 | TPM_LONG, | ||
205 | TPM_SHORT, | ||
206 | TPM_SHORT, | ||
207 | TPM_SHORT, /* 130 */ | ||
208 | TPM_MEDIUM, | ||
209 | TPM_UNDEFINED, | ||
210 | TPM_SHORT, | ||
211 | TPM_MEDIUM, | ||
212 | TPM_UNDEFINED, /* 135 */ | ||
213 | TPM_UNDEFINED, | ||
214 | TPM_UNDEFINED, | ||
215 | TPM_UNDEFINED, | ||
216 | TPM_UNDEFINED, | ||
217 | TPM_SHORT, /* 140 */ | ||
218 | TPM_SHORT, | ||
219 | TPM_UNDEFINED, | ||
220 | TPM_UNDEFINED, | ||
221 | TPM_UNDEFINED, | ||
222 | TPM_UNDEFINED, /* 145 */ | ||
223 | TPM_UNDEFINED, | ||
224 | TPM_UNDEFINED, | ||
225 | TPM_UNDEFINED, | ||
226 | TPM_UNDEFINED, | ||
227 | TPM_SHORT, /* 150 */ | ||
228 | TPM_MEDIUM, | ||
229 | TPM_MEDIUM, | ||
230 | TPM_SHORT, | ||
231 | TPM_SHORT, | ||
232 | TPM_UNDEFINED, /* 155 */ | ||
233 | TPM_UNDEFINED, | ||
234 | TPM_UNDEFINED, | ||
235 | TPM_UNDEFINED, | ||
236 | TPM_UNDEFINED, | ||
237 | TPM_SHORT, /* 160 */ | ||
238 | TPM_SHORT, | ||
239 | TPM_SHORT, | ||
240 | TPM_SHORT, | ||
241 | TPM_UNDEFINED, | ||
242 | TPM_UNDEFINED, /* 165 */ | ||
243 | TPM_UNDEFINED, | ||
244 | TPM_UNDEFINED, | ||
245 | TPM_UNDEFINED, | ||
246 | TPM_UNDEFINED, | ||
247 | TPM_LONG, /* 170 */ | ||
248 | TPM_UNDEFINED, | ||
249 | TPM_UNDEFINED, | ||
250 | TPM_UNDEFINED, | ||
251 | TPM_UNDEFINED, | ||
252 | TPM_UNDEFINED, /* 175 */ | ||
253 | TPM_UNDEFINED, | ||
254 | TPM_UNDEFINED, | ||
255 | TPM_UNDEFINED, | ||
256 | TPM_UNDEFINED, | ||
257 | TPM_MEDIUM, /* 180 */ | ||
258 | TPM_SHORT, | ||
259 | TPM_MEDIUM, | ||
260 | TPM_MEDIUM, | ||
261 | TPM_MEDIUM, | ||
262 | TPM_MEDIUM, /* 185 */ | ||
263 | TPM_SHORT, | ||
264 | TPM_UNDEFINED, | ||
265 | TPM_UNDEFINED, | ||
266 | TPM_UNDEFINED, | ||
267 | TPM_UNDEFINED, /* 190 */ | ||
268 | TPM_UNDEFINED, | ||
269 | TPM_UNDEFINED, | ||
270 | TPM_UNDEFINED, | ||
271 | TPM_UNDEFINED, | ||
272 | TPM_UNDEFINED, /* 195 */ | ||
273 | TPM_UNDEFINED, | ||
274 | TPM_UNDEFINED, | ||
275 | TPM_UNDEFINED, | ||
276 | TPM_UNDEFINED, | ||
277 | TPM_SHORT, /* 200 */ | ||
278 | TPM_UNDEFINED, | ||
279 | TPM_UNDEFINED, | ||
280 | TPM_UNDEFINED, | ||
281 | TPM_SHORT, | ||
282 | TPM_SHORT, /* 205 */ | ||
283 | TPM_SHORT, | ||
284 | TPM_SHORT, | ||
285 | TPM_SHORT, | ||
286 | TPM_SHORT, | ||
287 | TPM_MEDIUM, /* 210 */ | ||
288 | TPM_UNDEFINED, | ||
289 | TPM_MEDIUM, | ||
290 | TPM_MEDIUM, | ||
291 | TPM_MEDIUM, | ||
292 | TPM_UNDEFINED, /* 215 */ | ||
293 | TPM_MEDIUM, | ||
294 | TPM_UNDEFINED, | ||
295 | TPM_UNDEFINED, | ||
296 | TPM_SHORT, | ||
297 | TPM_SHORT, /* 220 */ | ||
298 | TPM_SHORT, | ||
299 | TPM_SHORT, | ||
300 | TPM_SHORT, | ||
301 | TPM_SHORT, | ||
302 | TPM_UNDEFINED, /* 225 */ | ||
303 | TPM_UNDEFINED, | ||
304 | TPM_UNDEFINED, | ||
305 | TPM_UNDEFINED, | ||
306 | TPM_UNDEFINED, | ||
307 | TPM_SHORT, /* 230 */ | ||
308 | TPM_LONG, | ||
309 | TPM_MEDIUM, | ||
310 | TPM_UNDEFINED, | ||
311 | TPM_UNDEFINED, | ||
312 | TPM_UNDEFINED, /* 235 */ | ||
313 | TPM_UNDEFINED, | ||
314 | TPM_UNDEFINED, | ||
315 | TPM_UNDEFINED, | ||
316 | TPM_UNDEFINED, | ||
317 | TPM_SHORT, /* 240 */ | ||
318 | TPM_UNDEFINED, | ||
319 | TPM_MEDIUM, | ||
320 | }; | ||
321 | |||
42 | static void user_reader_timeout(unsigned long ptr) | 322 | static void user_reader_timeout(unsigned long ptr) |
43 | { | 323 | { |
44 | struct tpm_chip *chip = (struct tpm_chip *) ptr; | 324 | struct tpm_chip *chip = (struct tpm_chip *) ptr; |
@@ -57,17 +337,43 @@ static void timeout_work(void *ptr) | |||
57 | } | 337 | } |
58 | 338 | ||
59 | /* | 339 | /* |
340 | * Returns max number of jiffies to wait | ||
341 | */ | ||
342 | unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, | ||
343 | u32 ordinal) | ||
344 | { | ||
345 | int duration_idx = TPM_UNDEFINED; | ||
346 | int duration = 0; | ||
347 | |||
348 | if (ordinal < TPM_MAX_ORDINAL) | ||
349 | duration_idx = tpm_ordinal_duration[ordinal]; | ||
350 | else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) < | ||
351 | TPM_MAX_PROTECTED_ORDINAL) | ||
352 | duration_idx = | ||
353 | tpm_protected_ordinal_duration[ordinal & | ||
354 | TPM_PROTECTED_ORDINAL_MASK]; | ||
355 | |||
356 | if (duration_idx != TPM_UNDEFINED) | ||
357 | duration = chip->vendor.duration[duration_idx] * HZ / 1000; | ||
358 | if (duration <= 0) | ||
359 | return 2 * 60 * HZ; | ||
360 | else | ||
361 | return duration; | ||
362 | } | ||
363 | EXPORT_SYMBOL_GPL(tpm_calc_ordinal_duration); | ||
364 | |||
365 | /* | ||
60 | * Internal kernel interface to transmit TPM commands | 366 | * Internal kernel interface to transmit TPM commands |
61 | */ | 367 | */ |
62 | static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | 368 | static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, |
63 | size_t bufsiz) | 369 | size_t bufsiz) |
64 | { | 370 | { |
65 | ssize_t rc; | 371 | ssize_t rc; |
66 | u32 count; | 372 | u32 count, ordinal; |
67 | unsigned long stop; | 373 | unsigned long stop; |
68 | 374 | ||
69 | count = be32_to_cpu(*((__be32 *) (buf + 2))); | 375 | count = be32_to_cpu(*((__be32 *) (buf + 2))); |
70 | 376 | ordinal = be32_to_cpu(*((__be32 *) (buf + 6))); | |
71 | if (count == 0) | 377 | if (count == 0) |
72 | return -ENODATA; | 378 | return -ENODATA; |
73 | if (count > bufsiz) { | 379 | if (count > bufsiz) { |
@@ -84,7 +390,7 @@ static ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf, | |||
84 | goto out; | 390 | goto out; |
85 | } | 391 | } |
86 | 392 | ||
87 | stop = jiffies + 2 * 60 * HZ; | 393 | stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal); |
88 | do { | 394 | do { |
89 | u8 status = chip->vendor.status(chip); | 395 | u8 status = chip->vendor.status(chip); |
90 | if ((status & chip->vendor.req_complete_mask) == | 396 | if ((status & chip->vendor.req_complete_mask) == |