Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/tpm/tpm.c
+++ new/usr/src/uts/common/io/tpm/tpm.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26
27 27 /*
28 28 * TPM 1.2 Driver for the TPMs that follow TIS v1.2
29 29 */
30 30
31 31 #include <sys/devops.h> /* used by dev_ops */
32 32 #include <sys/conf.h> /* used by dev_ops,cb_ops */
33 33 #include <sys/modctl.h> /* for _init,_info,_fini,mod_* */
34 34 #include <sys/ddi.h> /* used by all entry points */
35 35 #include <sys/sunddi.h> /* used by all entry points */
36 36 #include <sys/cmn_err.h> /* used for debug outputs */
37 37 #include <sys/types.h> /* used by prop_op, ddi_prop_op */
38 38
39 39 #include <sys/file.h> /* used by open, close */
40 40 #include <sys/errno.h> /* used by open,close,read,write */
41 41 #include <sys/open.h> /* used by open,close,read,write */
42 42 #include <sys/cred.h> /* used by open,close,read */
43 43 #include <sys/uio.h> /* used by read */
44 44 #include <sys/stat.h> /* defines S_IFCHR */
45 45
46 46 #include <sys/byteorder.h> /* for ntohs, ntohl, htons, htonl */
47 47
48 48 #ifdef sun4v
49 49 #include <sys/hypervisor_api.h>
50 50 #include <sys/hsvc.h>
51 51 #endif
52 52
53 53 #include <tss/platform.h> /* from SUNWtss */
54 54 #include <tss/tpm.h> /* from SUNWtss */
55 55
56 56 #include "tpm_tis.h"
57 57 #include "tpm_ddi.h"
58 58 #include "tpm_duration.h"
59 59
60 60 #define TPM_HEADER_SIZE 10
61 61 typedef enum {
62 62 TPM_TAG_OFFSET = 0,
63 63 TPM_PARAMSIZE_OFFSET = 2,
64 64 TPM_RETURN_OFFSET = 6,
65 65 TPM_COMMAND_CODE_OFFSET = 6,
66 66 } TPM_HEADER_OFFSET_T;
67 67
68 68 /*
69 69 * This is to address some TPMs that does not report the correct duration
70 70 * and timeouts. In our experience with the production TPMs, we encountered
71 71 * time errors such as GetCapability command from TPM reporting the timeout
72 72 * and durations in milliseconds rather than microseconds. Some other TPMs
73 73 * report the value 0's
74 74 *
75 75 * Short Duration is based on section 11.3.4 of TIS speciciation, that
76 76 * TPM_GetCapability (short duration) commands should not be longer than 750ms
77 77 * and that section 11.3.7 states that TPM_ContinueSelfTest (medium duration)
78 78 * should not be longer than 1 second.
79 79 */
80 80 #define DEFAULT_SHORT_DURATION 750000
81 81 #define DEFAULT_MEDIUM_DURATION 1000000
82 82 #define DEFAULT_LONG_DURATION 300000000
83 83 #define DEFAULT_TIMEOUT_A 750000
84 84 #define DEFAULT_TIMEOUT_B 2000000
85 85 #define DEFAULT_TIMEOUT_C 750000
86 86 #define DEFAULT_TIMEOUT_D 750000
87 87
88 88 /*
89 89 * In order to test the 'millisecond bug', we test if DURATIONS and TIMEOUTS
90 90 * are unreasonably low...such as 10 milliseconds (TPM isn't that fast).
91 91 * and 400 milliseconds for long duration
92 92 */
93 93 #define TEN_MILLISECONDS 10000 /* 10 milliseconds */
94 94 #define FOUR_HUNDRED_MILLISECONDS 400000 /* 4 hundred milliseconds */
95 95
96 96 #define DEFAULT_LOCALITY 0
97 97 /*
98 98 * TPM input/output buffer offsets
99 99 */
100 100
101 101 typedef enum {
102 102 TPM_CAP_RESPSIZE_OFFSET = 10,
103 103 TPM_CAP_RESP_OFFSET = 14,
104 104 } TPM_CAP_RET_OFFSET_T;
105 105
106 106 typedef enum {
107 107 TPM_CAP_TIMEOUT_A_OFFSET = 14,
108 108 TPM_CAP_TIMEOUT_B_OFFSET = 18,
109 109 TPM_CAP_TIMEOUT_C_OFFSET = 22,
110 110 TPM_CAP_TIMEOUT_D_OFFSET = 26,
111 111 } TPM_CAP_TIMEOUT_OFFSET_T;
112 112
113 113 typedef enum {
114 114 TPM_CAP_DUR_SHORT_OFFSET = 14,
115 115 TPM_CAP_DUR_MEDIUM_OFFSET = 18,
116 116 TPM_CAP_DUR_LONG_OFFSET = 22,
117 117 } TPM_CAP_DURATION_OFFSET_T;
118 118
119 119 #define TPM_CAP_VERSION_INFO_OFFSET 14
120 120 #define TPM_CAP_VERSION_INFO_SIZE 15
121 121
122 122 /*
123 123 * Internal TPM command functions
124 124 */
125 125 static int itpm_command(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz);
126 126 static int tpm_get_timeouts(tpm_state_t *tpm);
127 127 static int tpm_get_duration(tpm_state_t *tpm);
128 128 static int tpm_get_version(tpm_state_t *tpm);
129 129 static int tpm_continue_selftest(tpm_state_t *tpm);
130 130
131 131 /*
132 132 * Internal TIS related functions
133 133 */
134 134 static int tpm_wait_for_stat(tpm_state_t *, uint8_t, clock_t);
135 135 static clock_t tpm_get_ordinal_duration(tpm_state_t *, uint8_t);
136 136 static int tis_check_active_locality(tpm_state_t *, char);
137 137 static int tis_request_locality(tpm_state_t *, char);
138 138 static void tis_release_locality(tpm_state_t *, char, int);
139 139 static int tis_init(tpm_state_t *);
140 140 static uint8_t tis_get_status(tpm_state_t *);
141 141 static int tis_send_data(tpm_state_t *, uint8_t *, size_t);
142 142 static int tis_recv_data(tpm_state_t *, uint8_t *, size_t);
143 143
144 144 /* Auxilliary */
145 145 static int receive_data(tpm_state_t *, uint8_t *, size_t);
146 146 static inline int tpm_io_lock(tpm_state_t *);
147 147 static inline void tpm_unlock(tpm_state_t *);
148 148 static void tpm_cleanup(dev_info_t *, tpm_state_t *);
149 149
150 150 /*
151 151 * Sun DDI/DDK entry points
152 152 */
153 153
154 154 /* Declaration of autoconfig functions */
155 155 static int tpm_attach(dev_info_t *, ddi_attach_cmd_t);
156 156 static int tpm_detach(dev_info_t *, ddi_detach_cmd_t);
157 157 static int tpm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
158 158 static int tpm_quiesce(dev_info_t *);
159 159 /* End of autoconfig functions */
160 160
161 161 /* Declaration of driver entry point functions */
162 162 static int tpm_open(dev_t *, int, int, cred_t *);
163 163 static int tpm_close(dev_t, int, int, cred_t *);
164 164 static int tpm_read(dev_t, struct uio *, cred_t *);
165 165 static int tpm_write(dev_t, struct uio *, cred_t *);
166 166 /* End of driver entry point functions */
167 167
168 168 /* cb_ops structure */
169 169 static struct cb_ops tpm_cb_ops = {
170 170 tpm_open,
171 171 tpm_close,
172 172 nodev, /* no strategy - nodev returns ENXIO */
173 173 nodev, /* no print */
174 174 nodev, /* no dump */
175 175 tpm_read,
176 176 tpm_write,
177 177 nodev, /* no ioctl */
178 178 nodev, /* no devmap */
179 179 nodev, /* no mmap */
180 180 nodev, /* no segmap */
181 181 nochpoll, /* returns ENXIO for non-pollable devices */
182 182 ddi_prop_op,
183 183 NULL, /* streamtab struc */
184 184 D_MP, /* compatibility flags */
185 185 CB_REV, /* cb_ops revision number */
186 186 nodev, /* no aread */
187 187 nodev /* no awrite */
188 188 };
189 189
190 190 /* dev_ops structure */
191 191 static struct dev_ops tpm_dev_ops = {
192 192 DEVO_REV,
193 193 0, /* reference count */
194 194 tpm_getinfo,
195 195 nulldev, /* no identify - nulldev returns 0 */
196 196 nulldev,
197 197 tpm_attach,
198 198 tpm_detach,
199 199 nodev, /* no reset - nodev returns ENXIO */
200 200 &tpm_cb_ops,
201 201 (struct bus_ops *)NULL,
202 202 nodev, /* no power */
203 203 tpm_quiesce
204 204 };
205 205
↓ open down ↓ |
205 lines elided |
↑ open up ↑ |
206 206 /* modldrv structure */
207 207 static struct modldrv modldrv = {
208 208 &mod_driverops, /* Type: This is a driver */
209 209 "TPM 1.2 driver", /* Name of the module. */
210 210 &tpm_dev_ops
211 211 };
212 212
213 213 /* modlinkage structure */
214 214 static struct modlinkage tpm_ml = {
215 215 MODREV_1,
216 - &modldrv,
217 - NULL
216 + { &modldrv, NULL }
218 217 };
219 218
220 219
221 220 #ifdef KCF_TPM_RNG_PROVIDER
222 221
223 222 #define IDENT_TPMRNG "TPM Random Number Generator"
224 223
225 224 #include <sys/crypto/common.h>
226 225 #include <sys/crypto/impl.h>
227 226 #include <sys/crypto/spi.h>
228 227 /*
229 228 * CSPI information (entry points, provider info, etc.)
230 229 */
231 230 static void tpmrng_provider_status(crypto_provider_handle_t, uint_t *);
232 231
233 232 static crypto_control_ops_t tpmrng_control_ops = {
234 233 tpmrng_provider_status
235 234 };
236 235
237 236 static int tpmrng_seed_random(crypto_provider_handle_t, crypto_session_id_t,
238 237 uchar_t *, size_t, uint_t, uint32_t, crypto_req_handle_t);
239 238
240 239 static int tpmrng_generate_random(crypto_provider_handle_t,
241 240 crypto_session_id_t, uchar_t *, size_t, crypto_req_handle_t);
242 241
243 242 static crypto_random_number_ops_t tpmrng_random_number_ops = {
244 243 tpmrng_seed_random,
245 244 tpmrng_generate_random
246 245 };
247 246
248 247 static int tpmrng_ext_info(crypto_provider_handle_t,
249 248 crypto_provider_ext_info_t *,
250 249 crypto_req_handle_t);
251 250
252 251 static crypto_provider_management_ops_t tpmrng_extinfo_op = {
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
253 252 tpmrng_ext_info,
254 253 NULL,
255 254 NULL,
256 255 NULL
257 256 };
258 257
259 258 static int tpmrng_register(tpm_state_t *);
260 259 static int tpmrng_unregister(tpm_state_t *);
261 260
262 261 static crypto_ops_t tpmrng_crypto_ops = {
263 - &tpmrng_control_ops,
264 - NULL,
265 - NULL,
266 - NULL,
267 - NULL,
268 - NULL,
269 - NULL,
270 - NULL,
271 - &tpmrng_random_number_ops,
272 - NULL,
273 - NULL,
274 - NULL,
275 - &tpmrng_extinfo_op,
276 - NULL,
277 - NULL
262 + .co_control_ops = &tpmrng_control_ops,
263 + .co_random_ops = &tpmrng_random_number_ops,
264 + .co_provider_ops = &tpmrng_extinfo_op
278 265 };
279 266
280 267 static crypto_provider_info_t tpmrng_prov_info = {
281 268 CRYPTO_SPI_VERSION_2,
282 269 "TPM Random Number Provider",
283 270 CRYPTO_HW_PROVIDER,
284 271 NULL,
285 272 NULL,
286 273 &tpmrng_crypto_ops,
287 274 0,
288 275 NULL,
289 276 0,
290 277 NULL
291 278 };
292 279 #endif /* KCF_TPM_RNG_PROVIDER */
293 280
294 281 static void *statep = NULL;
295 282
296 283 /*
297 284 * Inline code to get exclusive lock on the TPM device and to make sure
298 285 * the device is not suspended. This grabs the primary TPM mutex (pm_mutex)
299 286 * and then checks the suspend status. If suspended, it will wait until
300 287 * the device is "resumed" before releasing the pm_mutex and continuing.
301 288 */
302 289 #define TPM_EXCLUSIVE_LOCK(tpm) { \
303 290 mutex_enter(&tpm->pm_mutex); \
304 291 while (tpm->suspended) \
305 292 cv_wait(&tpm->suspend_cv, &tpm->pm_mutex); \
306 293 mutex_exit(&tpm->pm_mutex); }
307 294
308 295 /*
309 296 * TPM accessor functions
310 297 */
311 298 #ifdef sun4v
312 299
313 300 extern uint64_t
314 301 hcall_tpm_get(uint64_t, uint64_t, uint64_t, uint64_t *);
315 302
316 303 extern uint64_t
317 304 hcall_tpm_put(uint64_t, uint64_t, uint64_t, uint64_t);
318 305
319 306 static inline uint8_t
320 307 tpm_get8(tpm_state_t *tpm, unsigned long offset)
321 308 {
322 309 uint64_t value;
323 310
324 311 ASSERT(tpm != NULL);
325 312 (void) hcall_tpm_get(tpm->locality, offset, sizeof (uint8_t), &value);
326 313 return ((uint8_t)value);
327 314 }
328 315
329 316 static inline uint32_t
330 317 tpm_get32(tpm_state_t *tpm, unsigned long offset)
331 318 {
332 319 uint64_t value;
333 320
334 321 ASSERT(tpm != NULL);
335 322 (void) hcall_tpm_get(tpm->locality, offset, sizeof (uint32_t), &value);
336 323 return ((uint32_t)value);
337 324 }
338 325
339 326 static inline void
340 327 tpm_put8(tpm_state_t *tpm, unsigned long offset, uint8_t value)
341 328 {
342 329 ASSERT(tpm != NULL);
343 330 (void) hcall_tpm_put(tpm->locality, offset, sizeof (uint8_t), value);
344 331 }
345 332
346 333 #else
347 334
348 335 static inline uint8_t
349 336 tpm_get8(tpm_state_t *tpm, unsigned long offset)
350 337 {
351 338 ASSERT(tpm != NULL);
352 339
353 340 return (ddi_get8(tpm->handle,
354 341 (uint8_t *)(TPM_LOCALITY_OFFSET(tpm->locality) |
355 342 (uintptr_t)tpm->addr + offset)));
356 343 }
357 344
358 345 static inline uint32_t
359 346 tpm_get32(tpm_state_t *tpm, unsigned long offset)
360 347 {
361 348 ASSERT(tpm != NULL);
362 349 return (ddi_get32(tpm->handle,
363 350 (uint32_t *)(TPM_LOCALITY_OFFSET(tpm->locality) |
364 351 (uintptr_t)tpm->addr + offset)));
365 352 }
366 353
367 354 static inline void
368 355 tpm_put8(tpm_state_t *tpm, unsigned long offset, uint8_t value)
369 356 {
370 357 ASSERT(tpm != NULL);
371 358 ddi_put8(tpm->handle,
372 359 (uint8_t *)(TPM_LOCALITY_OFFSET(tpm->locality) |
373 360 (uintptr_t)tpm->addr + offset), value);
374 361 }
375 362
376 363 #endif /* sun4v */
377 364
378 365 /*
379 366 * TPM commands to get the TPM's properties, e.g.,timeout
380 367 */
381 368 /*ARGSUSED*/
382 369 static int
383 370 tpm_quiesce(dev_info_t *dip)
384 371 {
385 372 return (DDI_SUCCESS);
386 373 }
387 374
388 375 static uint32_t
389 376 load32(uchar_t *ptr, uint32_t offset)
390 377 {
391 378 uint32_t val;
392 379 bcopy(ptr + offset, &val, sizeof (uint32_t));
393 380
394 381 return (ntohl(val));
395 382 }
396 383
397 384 /*
398 385 * Get the actual timeouts supported by the TPM by issuing TPM_GetCapability
399 386 * with the subcommand TPM_CAP_PROP_TIS_TIMEOUT
400 387 * TPM_GetCapability (TPM Main Part 3 Rev. 94, pg.38)
401 388 */
402 389 static int
403 390 tpm_get_timeouts(tpm_state_t *tpm)
404 391 {
405 392 int ret;
406 393 uint32_t timeout; /* in milliseconds */
407 394 uint32_t len;
408 395
409 396 /* The buffer size (30) needs room for 4 timeout values (uint32_t) */
410 397 uint8_t buf[30] = {
411 398 0, 193, /* TPM_TAG_RQU_COMMAND */
412 399 0, 0, 0, 22, /* paramsize in bytes */
413 400 0, 0, 0, 101, /* TPM_ORD_GetCapability */
414 401 0, 0, 0, 5, /* TPM_CAP_Prop */
415 402 0, 0, 0, 4, /* SUB_CAP size in bytes */
416 403 0, 0, 1, 21 /* TPM_CAP_PROP_TIS_TIMEOUT(0x115) */
417 404 };
418 405 char *myname = "tpm_get_timeout";
419 406
420 407 ASSERT(tpm != NULL);
421 408
422 409 ret = itpm_command(tpm, buf, sizeof (buf));
423 410 if (ret != DDI_SUCCESS) {
424 411 #ifdef DEBUG
425 412 cmn_err(CE_WARN, "!%s: itpm_command failed", myname);
426 413 #endif
427 414 return (DDI_FAILURE);
428 415 }
429 416
430 417 /*
431 418 * Get the length of the returned buffer
432 419 * Make sure that there are 4 timeout values returned
433 420 * length of the capability response is stored in data[10-13]
434 421 * Also the TPM is in network byte order
435 422 */
436 423 len = load32(buf, TPM_CAP_RESPSIZE_OFFSET);
437 424 if (len != 4 * sizeof (uint32_t)) {
438 425 #ifdef DEBUG
439 426 cmn_err(CE_WARN, "!%s: capability response size should be %d"
440 427 "instead len = %d",
441 428 myname, (int)(4 * sizeof (uint32_t)), (int)len);
442 429 #endif
443 430 return (DDI_FAILURE);
444 431 }
445 432
446 433 /* Get the four timeout's: a,b,c,d (they are 4 bytes long each) */
447 434 timeout = load32(buf, TPM_CAP_TIMEOUT_A_OFFSET);
448 435 if (timeout == 0) {
449 436 timeout = DEFAULT_TIMEOUT_A;
450 437 } else if (timeout < TEN_MILLISECONDS) {
451 438 /* timeout is in millisecond range (should be microseconds) */
452 439 timeout *= 1000;
453 440 }
454 441 tpm->timeout_a = drv_usectohz(timeout);
455 442
456 443 timeout = load32(buf, TPM_CAP_TIMEOUT_B_OFFSET);
457 444 if (timeout == 0) {
458 445 timeout = DEFAULT_TIMEOUT_B;
459 446 } else if (timeout < TEN_MILLISECONDS) {
460 447 /* timeout is in millisecond range (should be microseconds) */
461 448 timeout *= 1000;
462 449 }
463 450 tpm->timeout_b = drv_usectohz(timeout);
464 451
465 452 timeout = load32(buf, TPM_CAP_TIMEOUT_C_OFFSET);
466 453 if (timeout == 0) {
467 454 timeout = DEFAULT_TIMEOUT_C;
468 455 } else if (timeout < TEN_MILLISECONDS) {
469 456 /* timeout is in millisecond range (should be microseconds) */
470 457 timeout *= 1000;
471 458 }
472 459 tpm->timeout_c = drv_usectohz(timeout);
473 460
474 461 timeout = load32(buf, TPM_CAP_TIMEOUT_D_OFFSET);
475 462 if (timeout == 0) {
476 463 timeout = DEFAULT_TIMEOUT_D;
477 464 } else if (timeout < TEN_MILLISECONDS) {
478 465 /* timeout is in millisecond range (should be microseconds) */
479 466 timeout *= 1000;
480 467 }
481 468 tpm->timeout_d = drv_usectohz(timeout);
482 469
483 470 return (DDI_SUCCESS);
484 471 }
485 472
486 473 /*
487 474 * Get the actual timeouts supported by the TPM by issuing TPM_GetCapability
488 475 * with the subcommand TPM_CAP_PROP_TIS_DURATION
489 476 * TPM_GetCapability (TPM Main Part 3 Rev. 94, pg.38)
490 477 */
491 478 static int
492 479 tpm_get_duration(tpm_state_t *tpm) {
493 480 int ret;
494 481 uint32_t duration;
495 482 uint32_t len;
496 483 uint8_t buf[30] = {
497 484 0, 193, /* TPM_TAG_RQU_COMMAND */
498 485 0, 0, 0, 22, /* paramsize in bytes */
499 486 0, 0, 0, 101, /* TPM_ORD_GetCapability */
500 487 0, 0, 0, 5, /* TPM_CAP_Prop */
501 488 0, 0, 0, 4, /* SUB_CAP size in bytes */
502 489 0, 0, 1, 32 /* TPM_CAP_PROP_TIS_DURATION(0x120) */
503 490 };
504 491 char *myname = "tpm_get_duration";
505 492
506 493 ASSERT(tpm != NULL);
507 494
508 495 ret = itpm_command(tpm, buf, sizeof (buf));
509 496 if (ret != DDI_SUCCESS) {
510 497 #ifdef DEBUG
511 498 cmn_err(CE_WARN, "!%s: itpm_command failed with ret code: 0x%x",
512 499 myname, ret);
513 500 #endif
514 501 return (DDI_FAILURE);
515 502 }
516 503
517 504 /*
518 505 * Get the length of the returned buffer
519 506 * Make sure that there are 3 duration values (S,M,L: in that order)
520 507 * length of the capability response is stored in data[10-13]
521 508 * Also the TPM is in network byte order
522 509 */
523 510 len = load32(buf, TPM_CAP_RESPSIZE_OFFSET);
524 511 if (len != 3 * sizeof (uint32_t)) {
525 512 #ifdef DEBUG
526 513 cmn_err(CE_WARN, "!%s: capability response should be %d, "
527 514 "instead, it's %d",
528 515 myname, (int)(3 * sizeof (uint32_t)), (int)len);
529 516 #endif
530 517 return (DDI_FAILURE);
531 518 }
532 519
533 520 duration = load32(buf, TPM_CAP_DUR_SHORT_OFFSET);
534 521 if (duration == 0) {
535 522 duration = DEFAULT_SHORT_DURATION;
536 523 } else if (duration < TEN_MILLISECONDS) {
537 524 duration *= 1000;
538 525 }
539 526 tpm->duration[TPM_SHORT] = drv_usectohz(duration);
540 527
541 528 duration = load32(buf, TPM_CAP_DUR_MEDIUM_OFFSET);
542 529 if (duration == 0) {
543 530 duration = DEFAULT_MEDIUM_DURATION;
544 531 } else if (duration < TEN_MILLISECONDS) {
545 532 duration *= 1000;
546 533 }
547 534 tpm->duration[TPM_MEDIUM] = drv_usectohz(duration);
548 535
549 536 duration = load32(buf, TPM_CAP_DUR_LONG_OFFSET);
550 537 if (duration == 0) {
551 538 duration = DEFAULT_LONG_DURATION;
552 539 } else if (duration < FOUR_HUNDRED_MILLISECONDS) {
553 540 duration *= 1000;
554 541 }
555 542 tpm->duration[TPM_LONG] = drv_usectohz(duration);
556 543
557 544 /* Just make the undefined duration be the same as the LONG */
558 545 tpm->duration[TPM_UNDEFINED] = tpm->duration[TPM_LONG];
559 546
560 547 return (DDI_SUCCESS);
561 548 }
562 549
563 550 /*
564 551 * Get the actual timeouts supported by the TPM by issuing TPM_GetCapability
565 552 * with the subcommand TPM_CAP_PROP_TIS_DURATION
566 553 * TPM_GetCapability (TPM Main Part 3 Rev. 94, pg.38)
567 554 */
568 555 static int
569 556 tpm_get_version(tpm_state_t *tpm) {
570 557 int ret;
571 558 uint32_t len;
572 559 char vendorId[5];
573 560 /* If this buf is too small, the "vendor specific" data won't fit */
574 561 uint8_t buf[64] = {
575 562 0, 193, /* TPM_TAG_RQU_COMMAND */
576 563 0, 0, 0, 18, /* paramsize in bytes */
577 564 0, 0, 0, 101, /* TPM_ORD_GetCapability */
578 565 0, 0, 0, 0x1A, /* TPM_CAP_VERSION_VAL */
579 566 0, 0, 0, 0, /* SUB_CAP size in bytes */
580 567 };
581 568 char *myname = "tpm_get_version";
582 569
583 570 ASSERT(tpm != NULL);
584 571
585 572 ret = itpm_command(tpm, buf, sizeof (buf));
586 573 if (ret != DDI_SUCCESS) {
587 574 #ifdef DEBUG
588 575 cmn_err(CE_WARN, "!%s: itpm_command failed with ret code: 0x%x",
589 576 myname, ret);
590 577 #endif
591 578 return (DDI_FAILURE);
592 579 }
593 580
594 581 /*
595 582 * Get the length of the returned buffer.
596 583 */
597 584 len = load32(buf, TPM_CAP_RESPSIZE_OFFSET);
598 585 if (len < TPM_CAP_VERSION_INFO_SIZE) {
599 586 #ifdef DEBUG
600 587 cmn_err(CE_WARN, "!%s: capability response should be greater"
601 588 " than %d, instead, it's %d",
602 589 myname, TPM_CAP_VERSION_INFO_SIZE, len);
603 590 #endif
604 591 return (DDI_FAILURE);
605 592 }
606 593
607 594 bcopy(buf + TPM_CAP_VERSION_INFO_OFFSET, &tpm->vers_info,
608 595 TPM_CAP_VERSION_INFO_SIZE);
609 596
610 597 bcopy(tpm->vers_info.tpmVendorID, vendorId,
611 598 sizeof (tpm->vers_info.tpmVendorID));
612 599 vendorId[4] = '\0';
613 600
614 601 cmn_err(CE_NOTE, "!TPM found: Ver %d.%d, Rev %d.%d, "
615 602 "SpecLevel %d, errataRev %d, VendorId '%s'",
616 603 tpm->vers_info.version.major, /* Version */
617 604 tpm->vers_info.version.minor,
618 605 tpm->vers_info.version.revMajor, /* Revision */
619 606 tpm->vers_info.version.revMinor,
620 607 (int)ntohs(tpm->vers_info.specLevel),
621 608 tpm->vers_info.errataRev,
622 609 vendorId);
623 610
624 611 /*
625 612 * This driver only supports TPM Version 1.2
626 613 */
627 614 if (tpm->vers_info.version.major != 1 &&
628 615 tpm->vers_info.version.minor != 2) {
629 616 cmn_err(CE_WARN, "!%s: Unsupported TPM version (%d.%d)",
630 617 myname,
631 618 tpm->vers_info.version.major, /* Version */
632 619 tpm->vers_info.version.minor);
633 620 return (DDI_FAILURE);
634 621 }
635 622
636 623 return (DDI_SUCCESS);
637 624 }
638 625
639 626 /*
640 627 * To prevent the TPM from complaining that certain functions are not tested
641 628 * we run this command when the driver attaches.
642 629 * For details see Section 4.2 of TPM Main Part 3 Command Specification
643 630 */
644 631 static int
645 632 tpm_continue_selftest(tpm_state_t *tpm) {
646 633 int ret;
647 634 uint8_t buf[10] = {
648 635 0, 193, /* TPM_TAG_RQU COMMAND */
649 636 0, 0, 0, 10, /* paramsize in bytes */
650 637 0, 0, 0, 83 /* TPM_ORD_ContinueSelfTest */
651 638 };
652 639 char *myname = "tpm_continue_selftest";
653 640
654 641 /* Need a longer timeout */
655 642 ret = itpm_command(tpm, buf, sizeof (buf));
656 643 if (ret != DDI_SUCCESS) {
657 644 #ifdef DEBUG
658 645 cmn_err(CE_WARN, "!%s: itpm_command failed", myname);
659 646 #endif
660 647 return (DDI_FAILURE);
661 648 }
662 649
663 650 return (DDI_SUCCESS);
664 651 }
665 652 /*
666 653 * Auxilary Functions
667 654 */
668 655
669 656 /*
670 657 * Find out how long we should wait for the TPM command to complete a command
671 658 */
672 659 static clock_t
673 660 tpm_get_ordinal_duration(tpm_state_t *tpm, uint8_t ordinal)
674 661 {
675 662 uint8_t index;
676 663 char *myname = "tpm_get_ordinal_duration";
677 664
678 665 ASSERT(tpm != NULL);
679 666
680 667 /* Default and failure case for IFX */
681 668 /* Is it a TSC_ORDINAL? */
682 669 if (ordinal & TSC_ORDINAL_MASK) {
683 670 if (ordinal > TSC_ORDINAL_MAX) {
684 671 #ifdef DEBUG
685 672 cmn_err(CE_WARN,
686 673 "!%s: tsc ordinal: %d exceeds MAX: %d",
687 674 myname, ordinal, TSC_ORDINAL_MAX);
688 675 #endif
689 676 return (0);
690 677 }
691 678 index = tsc_ords_duration[ordinal];
692 679 } else {
693 680 if (ordinal > TPM_ORDINAL_MAX) {
694 681 #ifdef DEBUG
695 682 cmn_err(CE_WARN,
696 683 "!%s: ordinal %d exceeds MAX: %d",
697 684 myname, ordinal, TPM_ORDINAL_MAX);
698 685 #endif
699 686 return (0);
700 687 }
701 688 index = tpm_ords_duration[ordinal];
702 689 }
703 690
704 691 if (index > TPM_DURATION_MAX_IDX) {
705 692 #ifdef DEBUG
706 693 cmn_err(CE_WARN, "!%s: duration index '%d' is out of bounds",
707 694 myname, index);
708 695 #endif
709 696 return (0);
710 697 }
711 698 return (tpm->duration[index]);
712 699 }
713 700
714 701 /*
715 702 * Internal TPM Transmit Function:
716 703 * Calls implementation specific sendto and receive
717 704 * The code assumes that the buffer is in network byte order
718 705 */
719 706 static int
720 707 itpm_command(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz)
721 708 {
722 709 int ret;
723 710 uint32_t count;
724 711 char *myname = "itpm_command";
725 712
726 713 ASSERT(tpm != NULL && buf != NULL);
727 714
728 715 /* The byte order is network byte order so convert it */
729 716 count = load32(buf, TPM_PARAMSIZE_OFFSET);
730 717
731 718 if (count == 0 || (count > bufsiz)) {
732 719 #ifdef DEBUG
733 720 cmn_err(CE_WARN, "!%s: invalid byte count value "
734 721 "(%d > bufsiz %d)", myname, (int)count, (int)bufsiz);
735 722 #endif
736 723 return (DDI_FAILURE);
737 724 }
738 725
739 726 /* Send the command */
740 727 ret = tis_send_data(tpm, buf, count);
741 728 if (ret != DDI_SUCCESS) {
742 729 #ifdef DEBUG
743 730 cmn_err(CE_WARN, "!%s: tis_send_data failed with error %x",
744 731 myname, ret);
745 732 #endif
746 733 return (DDI_FAILURE);
747 734 }
748 735
749 736 /*
750 737 * Now receive the data from the tpm
751 738 * Should at least receive "the common" 10 bytes (TPM_HEADER_SIZE)
752 739 */
753 740 ret = tis_recv_data(tpm, buf, bufsiz);
754 741 if (ret < TPM_HEADER_SIZE) {
755 742 #ifdef DEBUG
756 743 cmn_err(CE_WARN, "!%s: tis_recv_data failed", myname);
757 744 #endif
758 745 return (DDI_FAILURE);
759 746 }
760 747
761 748 /* Check the return code */
762 749 ret = load32(buf, TPM_RETURN_OFFSET);
763 750 if (ret != TPM_SUCCESS) {
764 751 if (ret == TPM_E_DEACTIVATED)
765 752 cmn_err(CE_WARN, "!%s: TPM is deactivated", myname);
766 753 else if (ret == TPM_E_DISABLED)
767 754 cmn_err(CE_WARN, "!%s: TPM is disabled", myname);
768 755 else
769 756 cmn_err(CE_WARN, "!%s: TPM error code 0x%0x",
770 757 myname, ret);
771 758 return (DDI_FAILURE);
772 759 }
773 760
774 761 return (DDI_SUCCESS);
775 762 }
776 763
777 764 /*
778 765 * Whenever the driver wants to write to the DATA_IO register, it must need
779 766 * to figure out the burstcount. This is the amount of bytes it can write
780 767 * before having to wait for long LPC bus cycle
781 768 *
782 769 * Returns: 0 if error, burst count if sucess
783 770 */
784 771 static uint16_t
785 772 tpm_get_burstcount(tpm_state_t *tpm) {
786 773 clock_t stop;
787 774 uint16_t burstcnt;
788 775
789 776 ASSERT(tpm != NULL);
790 777
791 778 /*
792 779 * Spec says timeout should be TIMEOUT_D
793 780 * burst count is TPM_STS bits 8..23
794 781 */
795 782 stop = ddi_get_lbolt() + tpm->timeout_d;
796 783 do {
797 784 /*
798 785 * burstcnt is stored as a little endian value
799 786 * 'ntohs' doesn't work since the value is not word-aligned
800 787 */
801 788 burstcnt = tpm_get8(tpm, TPM_STS + 1);
802 789 burstcnt += tpm_get8(tpm, TPM_STS + 2) << 8;
803 790
804 791 if (burstcnt)
805 792 return (burstcnt);
806 793
807 794 delay(tpm->timeout_poll);
808 795 } while (ddi_get_lbolt() < stop);
809 796
810 797 return (0);
811 798 }
812 799
813 800 /*
814 801 * Writing 1 to TPM_STS_CMD_READY bit in TPM_STS will do the following:
815 802 * 1. The TPM will clears IO buffers if any
816 803 * 2. The TPM will enters either Idle or Ready state within TIMEOUT_B
817 804 * (checked in the calling function)
818 805 */
819 806 static void
820 807 tpm_set_ready(tpm_state_t *tpm) {
821 808 tpm_put8(tpm, TPM_STS, TPM_STS_CMD_READY);
822 809 }
823 810
824 811 static int
825 812 receive_data(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz) {
826 813 int size = 0;
827 814 int retried = 0;
828 815 uint8_t stsbits;
829 816
830 817 /* A number of consecutive bytes that can be written to TPM */
831 818 uint16_t burstcnt;
832 819
833 820 ASSERT(tpm != NULL && buf != NULL);
834 821 retry:
835 822 while (size < bufsiz &&
836 823 (tpm_wait_for_stat(tpm,
837 824 (TPM_STS_DATA_AVAIL|TPM_STS_VALID),
838 825 tpm->timeout_c) == DDI_SUCCESS)) {
839 826 /*
840 827 * Burstcount should be available within TIMEOUT_D
841 828 * after STS is set to valid
842 829 * burstcount is dynamic, so have to get it each time
843 830 */
844 831 burstcnt = tpm_get_burstcount(tpm);
845 832 for (; burstcnt > 0 && size < bufsiz; burstcnt--) {
846 833 buf[size++] = tpm_get8(tpm, TPM_DATA_FIFO);
847 834 }
848 835 }
849 836 stsbits = tis_get_status(tpm);
850 837 /* check to see if we need to retry (just once) */
851 838 if (size < bufsiz && !(stsbits & TPM_STS_DATA_AVAIL) && retried == 0) {
852 839 /* issue responseRetry (TIS 1.2 pg 54) */
853 840 tpm_put8(tpm, TPM_STS, TPM_STS_RESPONSE_RETRY);
854 841 /* update the retry counter so we only retry once */
855 842 retried++;
856 843 /* reset the size to 0 and reread the entire response */
857 844 size = 0;
858 845 goto retry;
859 846 }
860 847 return (size);
861 848 }
862 849
863 850 /* Receive the data from the TPM */
864 851 static int
865 852 tis_recv_data(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz) {
866 853 int ret;
867 854 int size = 0;
868 855 uint32_t expected, status;
869 856 uint32_t cmdresult;
870 857 char *myname = "tis_recv_data";
871 858
872 859 ASSERT(tpm != NULL && buf != NULL);
873 860
874 861 if (bufsiz < TPM_HEADER_SIZE) {
875 862 /* There should be at least tag, paramsize, return code */
876 863 #ifdef DEBUG
877 864 cmn_err(CE_WARN, "!%s: received data should contain at least "
878 865 "the header which is %d bytes long",
879 866 myname, TPM_HEADER_SIZE);
880 867 #endif
881 868 goto OUT;
882 869 }
883 870
884 871 /* Read tag(2 bytes), paramsize(4), and result(4) */
885 872 size = receive_data(tpm, buf, TPM_HEADER_SIZE);
886 873 if (size < TPM_HEADER_SIZE) {
887 874 #ifdef DEBUG
888 875 cmn_err(CE_WARN, "!%s: recv TPM_HEADER failed, size = %d",
889 876 myname, size);
890 877 #endif
891 878 goto OUT;
892 879 }
893 880
894 881 cmdresult = load32(buf, TPM_RETURN_OFFSET);
895 882
896 883 /* Get 'paramsize'(4 bytes)--it includes tag and paramsize */
897 884 expected = load32(buf, TPM_PARAMSIZE_OFFSET);
898 885 if (expected > bufsiz) {
899 886 #ifdef DEBUG
900 887 cmn_err(CE_WARN, "!%s: paramSize is bigger "
901 888 "than the requested size: paramSize=%d bufsiz=%d result=%d",
902 889 myname, (int)expected, (int)bufsiz, cmdresult);
903 890 #endif
904 891 goto OUT;
905 892 }
906 893
907 894 /* Read in the rest of the data from the TPM */
908 895 size += receive_data(tpm, (uint8_t *)&buf[TPM_HEADER_SIZE],
909 896 expected - TPM_HEADER_SIZE);
910 897 if (size < expected) {
911 898 #ifdef DEBUG
912 899 cmn_err(CE_WARN, "!%s: received data length (%d) "
913 900 "is less than expected (%d)", myname, size, expected);
914 901 #endif
915 902 goto OUT;
916 903 }
917 904
918 905 /* The TPM MUST set the state to stsValid within TIMEOUT_C */
919 906 ret = tpm_wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c);
920 907
921 908 status = tis_get_status(tpm);
922 909 if (ret != DDI_SUCCESS) {
923 910 #ifdef DEBUG
924 911 cmn_err(CE_WARN, "!%s: TPM didn't set stsValid after its I/O: "
925 912 "status = 0x%08X", myname, status);
926 913 #endif
927 914 goto OUT;
928 915 }
929 916
930 917 /* There is still more data? */
931 918 if (status & TPM_STS_DATA_AVAIL) {
932 919 #ifdef DEBUG
933 920 cmn_err(CE_WARN, "!%s: TPM_STS_DATA_AVAIL is set:0x%08X",
934 921 myname, status);
935 922 #endif
936 923 goto OUT;
937 924 }
938 925
939 926 /*
940 927 * Release the control of the TPM after we are done with it
941 928 * it...so others can also get a chance to send data
942 929 */
943 930 tis_release_locality(tpm, tpm->locality, 0);
944 931
945 932 OUT:
946 933 tpm_set_ready(tpm);
947 934 tis_release_locality(tpm, tpm->locality, 0);
948 935 return (size);
949 936 }
950 937
951 938 /*
952 939 * Send the data (TPM commands) to the Data IO register
953 940 */
954 941 static int
955 942 tis_send_data(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz) {
956 943 int ret;
957 944 uint8_t status;
958 945 uint16_t burstcnt;
959 946 uint32_t ordinal;
960 947 size_t count = 0;
961 948 char *myname = "tis_send_data";
962 949
963 950 ASSERT(tpm != NULL && buf != NULL);
964 951
965 952 if (bufsiz == 0) {
966 953 #ifdef DEBUG
967 954 cmn_err(CE_WARN, "!%s: bufsiz arg is zero", myname);
968 955 #endif
969 956 return (DDI_FAILURE);
970 957 }
971 958
972 959 /* Put the TPM in ready state */
973 960 status = tis_get_status(tpm);
974 961
975 962 if (!(status & TPM_STS_CMD_READY)) {
976 963 tpm_set_ready(tpm);
977 964 ret = tpm_wait_for_stat(tpm, TPM_STS_CMD_READY, tpm->timeout_b);
978 965 if (ret != DDI_SUCCESS) {
979 966 #ifdef DEBUG
980 967 cmn_err(CE_WARN, "!%s: could not put the TPM "
981 968 "in the command ready state:"
982 969 "tpm_wait_for_stat returned error",
983 970 myname);
984 971 #endif
985 972 goto FAIL;
986 973 }
987 974 }
988 975
989 976 /*
990 977 * Now we are ready to send command
991 978 * TPM's burstcount dictates how many bytes we can write at a time
992 979 * Burstcount is dynamic if INTF_CAPABILITY for static burstcount is
993 980 * not set.
994 981 */
995 982 while (count < bufsiz - 1) {
996 983 burstcnt = tpm_get_burstcount(tpm);
997 984 if (burstcnt == 0) {
998 985 #ifdef DEBUG
999 986 cmn_err(CE_WARN, "!%s: tpm_get_burstcnt returned error",
1000 987 myname);
1001 988 #endif
1002 989 ret = DDI_FAILURE;
1003 990 goto FAIL;
1004 991 }
1005 992
1006 993 for (; burstcnt > 0 && count < bufsiz - 1; burstcnt--) {
1007 994 tpm_put8(tpm, TPM_DATA_FIFO, buf[count]);
1008 995 count++;
1009 996 }
1010 997 /* Wait for TPM to indicate that it is ready for more data */
1011 998 ret = tpm_wait_for_stat(tpm,
1012 999 (TPM_STS_VALID | TPM_STS_DATA_EXPECT), tpm->timeout_c);
1013 1000 if (ret != DDI_SUCCESS) {
1014 1001 #ifdef DEBUG
1015 1002 cmn_err(CE_WARN, "!%s: TPM didn't enter STS_VALID "
1016 1003 "state", myname);
1017 1004 #endif
1018 1005 goto FAIL;
1019 1006 }
1020 1007 }
1021 1008 /* We can't exit the loop above unless we wrote bufsiz-1 bytes */
1022 1009
1023 1010 /* Write last byte */
1024 1011 tpm_put8(tpm, TPM_DATA_FIFO, buf[count]);
1025 1012 count++;
1026 1013
1027 1014 /* Wait for the TPM to enter Valid State */
1028 1015 ret = tpm_wait_for_stat(tpm, TPM_STS_VALID, tpm->timeout_c);
1029 1016 if (ret == DDI_FAILURE) {
1030 1017 #ifdef DEBUG
1031 1018 cmn_err(CE_WARN, "!%s: tpm didn't enter STS_VALID state",
1032 1019 myname);
1033 1020 #endif
1034 1021 goto FAIL;
1035 1022 }
1036 1023
1037 1024 status = tis_get_status(tpm);
1038 1025 /* The TPM should NOT be expecing more data at this point */
1039 1026 if ((status & TPM_STS_DATA_EXPECT) != 0) {
1040 1027 #ifdef DEBUG
1041 1028 cmn_err(CE_WARN, "!%s: DATA_EXPECT should not be set after "
1042 1029 "writing the last byte: status=0x%08X", myname, status);
1043 1030 #endif
1044 1031 ret = DDI_FAILURE;
1045 1032 goto FAIL;
1046 1033 }
1047 1034
1048 1035 /*
1049 1036 * Final step: Writing TPM_STS_GO to TPM_STS
1050 1037 * register will actually send the command.
1051 1038 */
1052 1039 tpm_put8(tpm, TPM_STS, TPM_STS_GO);
1053 1040
1054 1041 /* Ordinal/Command_code is located in buf[6..9] */
1055 1042 ordinal = load32(buf, TPM_COMMAND_CODE_OFFSET);
1056 1043
1057 1044 ret = tpm_wait_for_stat(tpm, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
1058 1045 tpm_get_ordinal_duration(tpm, ordinal));
1059 1046 if (ret == DDI_FAILURE) {
1060 1047 #ifdef DEBUG
1061 1048 status = tis_get_status(tpm);
1062 1049 if (!(status & TPM_STS_DATA_AVAIL) ||
1063 1050 !(status & TPM_STS_VALID)) {
1064 1051 cmn_err(CE_WARN, "!%s: TPM not ready or valid "
1065 1052 "(ordinal = %d timeout = %ld status = 0x%0x)",
1066 1053 myname, ordinal,
1067 1054 tpm_get_ordinal_duration(tpm, ordinal),
1068 1055 status);
1069 1056 } else {
1070 1057 cmn_err(CE_WARN, "!%s: tpm_wait_for_stat "
1071 1058 "(DATA_AVAIL | VALID) failed status = 0x%0X",
1072 1059 myname, status);
1073 1060 }
1074 1061 #endif
1075 1062 goto FAIL;
1076 1063 }
1077 1064 return (DDI_SUCCESS);
1078 1065
1079 1066 FAIL:
1080 1067 tpm_set_ready(tpm);
1081 1068 tis_release_locality(tpm, tpm->locality, 0);
1082 1069 return (ret);
1083 1070 }
1084 1071
1085 1072 /*
1086 1073 * Clear XrequestUse and Xactivelocality, where X is the current locality
1087 1074 */
1088 1075 static void
1089 1076 tis_release_locality(tpm_state_t *tpm, char locality, int force) {
1090 1077 ASSERT(tpm != NULL && locality >= 0 && locality < 5);
1091 1078
1092 1079 if (force ||
1093 1080 (tpm_get8(tpm, TPM_ACCESS) &
1094 1081 (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) ==
1095 1082 (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) {
1096 1083 /*
1097 1084 * Writing 1 to active locality bit in TPM_ACCESS
1098 1085 * register reliquishes the control of the locality
1099 1086 */
1100 1087 tpm_put8(tpm, TPM_ACCESS, TPM_ACCESS_ACTIVE_LOCALITY);
1101 1088 }
1102 1089 }
1103 1090
1104 1091 /*
1105 1092 * Checks whether the given locality is active
1106 1093 * Use TPM_ACCESS register and the masks TPM_ACCESS_VALID,TPM_ACTIVE_LOCALITY
1107 1094 */
1108 1095 static int
1109 1096 tis_check_active_locality(tpm_state_t *tpm, char locality) {
1110 1097 uint8_t access_bits;
1111 1098 uint8_t old_locality;
1112 1099
1113 1100 ASSERT(tpm != NULL && locality >= 0 && locality < 5);
1114 1101
1115 1102 old_locality = tpm->locality;
1116 1103 tpm->locality = locality;
1117 1104
1118 1105 /* Just check to see if the requested locality works */
1119 1106 access_bits = tpm_get8(tpm, TPM_ACCESS);
1120 1107 access_bits &= (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID);
1121 1108
1122 1109 /* this was just a check, not a request to switch */
1123 1110 tpm->locality = old_locality;
1124 1111
1125 1112 if (access_bits == (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
1126 1113 return (DDI_SUCCESS);
1127 1114 } else {
1128 1115 return (DDI_FAILURE);
1129 1116 }
1130 1117 }
1131 1118
1132 1119 /* Request the TPM to be in the given locality */
1133 1120 static int
1134 1121 tis_request_locality(tpm_state_t *tpm, char locality) {
1135 1122 clock_t timeout;
1136 1123 int ret;
1137 1124 char *myname = "tis_request_locality";
1138 1125
1139 1126 ASSERT(tpm != NULL && locality >= 0 && locality < 5);
1140 1127
1141 1128 ret = tis_check_active_locality(tpm, locality);
1142 1129
1143 1130 if (ret == DDI_SUCCESS) {
1144 1131 /* Locality is already active */
1145 1132 tpm->locality = locality;
1146 1133 return (DDI_SUCCESS);
1147 1134 }
1148 1135
1149 1136 tpm_put8(tpm, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
1150 1137 timeout = ddi_get_lbolt() + tpm->timeout_a;
1151 1138
1152 1139 /* Using polling */
1153 1140 while (tis_check_active_locality(tpm, locality)
1154 1141 != DDI_SUCCESS) {
1155 1142 if (ddi_get_lbolt() >= timeout) {
1156 1143 #ifdef DEBUG
1157 1144 cmn_err(CE_WARN, "!%s: (interrupt-disabled) "
1158 1145 "tis_request_locality timed out (timeout_a = %ld)",
1159 1146 myname, tpm->timeout_a);
1160 1147 #endif
1161 1148 return (DDI_FAILURE);
1162 1149 }
1163 1150 delay(tpm->timeout_poll);
1164 1151 }
1165 1152
1166 1153 tpm->locality = locality;
1167 1154 return (DDI_SUCCESS);
1168 1155 }
1169 1156
1170 1157 /* Read the status register */
1171 1158 static uint8_t
1172 1159 tis_get_status(tpm_state_t *tpm) {
1173 1160 return (tpm_get8(tpm, TPM_STS));
1174 1161 }
1175 1162
1176 1163 static int
1177 1164 tpm_wait_for_stat(tpm_state_t *tpm, uint8_t mask, clock_t timeout) {
1178 1165 char *myname = "tpm_wait_for_stat";
1179 1166 clock_t absolute_timeout = ddi_get_lbolt() + timeout;
1180 1167
1181 1168 /* Using polling */
1182 1169 while ((tis_get_status(tpm) & mask) != mask) {
1183 1170 if (ddi_get_lbolt() >= absolute_timeout) {
1184 1171 /* Timeout reached */
1185 1172 #ifdef DEBUG
1186 1173 cmn_err(CE_WARN, "!%s: using "
1187 1174 "polling - reached timeout (%ld usecs)",
1188 1175 myname, drv_hztousec(timeout));
1189 1176 #endif
1190 1177 return (DDI_FAILURE);
1191 1178 }
1192 1179 delay(tpm->timeout_poll);
1193 1180 }
1194 1181 return (DDI_SUCCESS);
1195 1182 }
1196 1183
1197 1184 /*
1198 1185 * Initialize TPM device
1199 1186 * 1. Find out supported interrupt capabilities
1200 1187 * 2. Set up interrupt handler if supported (some BIOSes don't support
1201 1188 * interrupts for TPMS, in which case we set up polling)
1202 1189 * 3. Determine timeouts and commands duration
1203 1190 */
1204 1191 static int
1205 1192 tis_init(tpm_state_t *tpm) {
1206 1193 uint32_t intf_caps;
1207 1194 int ret;
1208 1195 char *myname = "tis_init";
1209 1196
1210 1197 /*
1211 1198 * Temporarily set up timeouts before we get the real timeouts
1212 1199 * by issuing TPM_CAP commands (but to issue TPM_CAP commands,
1213 1200 * you need TIMEOUTs defined...chicken and egg problem here.
1214 1201 * TPM timeouts: Convert the milliseconds to clock cycles
1215 1202 */
1216 1203 tpm->timeout_a = drv_usectohz(TIS_TIMEOUT_A);
1217 1204 tpm->timeout_b = drv_usectohz(TIS_TIMEOUT_B);
1218 1205 tpm->timeout_c = drv_usectohz(TIS_TIMEOUT_C);
1219 1206 tpm->timeout_d = drv_usectohz(TIS_TIMEOUT_D);
1220 1207 /*
1221 1208 * Do the same with the duration (real duration will be filled out
1222 1209 * when we call TPM_GetCapability to get the duration values from
1223 1210 * the TPM itself).
1224 1211 */
1225 1212 tpm->duration[TPM_SHORT] = drv_usectohz(TPM_DEFAULT_DURATION);
1226 1213 tpm->duration[TPM_MEDIUM] = drv_usectohz(TPM_DEFAULT_DURATION);
1227 1214 tpm->duration[TPM_LONG] = drv_usectohz(TPM_DEFAULT_DURATION);
1228 1215 tpm->duration[TPM_UNDEFINED] = drv_usectohz(TPM_DEFAULT_DURATION);
1229 1216
1230 1217 /* Find out supported capabilities */
1231 1218 intf_caps = tpm_get32(tpm, TPM_INTF_CAP);
1232 1219
1233 1220 /* Upper 3 bytes should always return 0 */
1234 1221 if (intf_caps & 0x7FFFFF00) {
1235 1222 cmn_err(CE_WARN, "!%s: bad intf_caps value 0x%0X",
1236 1223 myname, intf_caps);
1237 1224 return (DDI_FAILURE);
1238 1225 }
1239 1226
1240 1227 /* These two interrupts are mandatory */
1241 1228 if (!(intf_caps & TPM_INTF_INT_LOCALITY_CHANGE_INT)) {
1242 1229 cmn_err(CE_WARN,
1243 1230 "!%s: Mandatory capability Locality Change Int "
1244 1231 "not supported", myname);
1245 1232 return (DDI_FAILURE);
1246 1233 }
1247 1234 if (!(intf_caps & TPM_INTF_INT_DATA_AVAIL_INT)) {
1248 1235 cmn_err(CE_WARN, "!%s: Mandatory capability Data Available Int "
1249 1236 "not supported.", myname);
1250 1237 return (DDI_FAILURE);
1251 1238 }
1252 1239
1253 1240 /*
1254 1241 * Before we start writing anything to TPM's registers,
1255 1242 * make sure we are in locality 0
1256 1243 */
1257 1244 ret = tis_request_locality(tpm, DEFAULT_LOCALITY);
1258 1245 if (ret != DDI_SUCCESS) {
1259 1246 cmn_err(CE_WARN, "!%s: Unable to request locality %d", myname,
1260 1247 DEFAULT_LOCALITY);
1261 1248 return (DDI_FAILURE);
1262 1249 } /* Now we can refer to the locality as tpm->locality */
1263 1250
1264 1251 tpm->timeout_poll = drv_usectohz(TPM_POLLING_TIMEOUT);
1265 1252 tpm->intr_enabled = 0;
1266 1253
1267 1254 /* Get the real timeouts from the TPM */
1268 1255 ret = tpm_get_timeouts(tpm);
1269 1256 if (ret != DDI_SUCCESS) {
1270 1257 cmn_err(CE_WARN, "!%s: tpm_get_timeouts error", myname);
1271 1258 return (DDI_FAILURE);
1272 1259 }
1273 1260
1274 1261 ret = tpm_get_duration(tpm);
1275 1262 if (ret != DDI_SUCCESS) {
1276 1263 cmn_err(CE_WARN, "!%s: tpm_get_duration error", myname);
1277 1264 return (DDI_FAILURE);
1278 1265 }
1279 1266
1280 1267 /* This gets the TPM version information */
1281 1268 ret = tpm_get_version(tpm);
1282 1269 if (ret != DDI_SUCCESS) {
1283 1270 cmn_err(CE_WARN, "!%s: tpm_get_version error", myname);
1284 1271 return (DDI_FAILURE);
1285 1272 }
1286 1273
1287 1274 /*
1288 1275 * Unless the TPM completes the test of its commands,
1289 1276 * it can return an error when the untested commands are called
1290 1277 */
1291 1278 ret = tpm_continue_selftest(tpm);
1292 1279 if (ret != DDI_SUCCESS) {
1293 1280 cmn_err(CE_WARN, "!%s: tpm_continue_selftest error", myname);
1294 1281 return (DDI_FAILURE);
1295 1282 }
1296 1283 return (DDI_SUCCESS);
1297 1284 }
1298 1285
1299 1286 /*
1300 1287 * Module Entry points
1301 1288 */
1302 1289 int
1303 1290 _init(void)
1304 1291 {
1305 1292 int ret;
1306 1293
1307 1294 ret = ddi_soft_state_init(&statep, sizeof (tpm_state_t), 1);
1308 1295 if (ret) {
1309 1296 #ifdef DEBUG
1310 1297 cmn_err(CE_WARN, "!ddi_soft_state_init failed: %d", ret);
1311 1298 #endif
1312 1299 return (ret);
1313 1300 }
1314 1301 ret = mod_install(&tpm_ml);
1315 1302 if (ret != 0) {
1316 1303 #ifdef DEBUG
1317 1304 cmn_err(CE_WARN, "!_init: mod_install returned non-zero");
1318 1305 #endif
1319 1306 ddi_soft_state_fini(&statep);
1320 1307 return (ret);
1321 1308 }
1322 1309
1323 1310 return (ret);
1324 1311 }
1325 1312
1326 1313 int
1327 1314 _info(struct modinfo *modinfop)
1328 1315 {
1329 1316 int ret;
1330 1317 ret = mod_info(&tpm_ml, modinfop);
1331 1318 #ifdef DEBUG
1332 1319 if (ret == 0)
1333 1320 cmn_err(CE_WARN, "!mod_info failed: %d", ret);
1334 1321 #endif
1335 1322
1336 1323 return (ret);
1337 1324 }
1338 1325
1339 1326 int
1340 1327 _fini()
1341 1328 {
1342 1329 int ret;
1343 1330
1344 1331 ret = mod_remove(&tpm_ml);
1345 1332 if (ret != 0)
1346 1333 return (ret);
1347 1334
1348 1335 ddi_soft_state_fini(&statep);
1349 1336
1350 1337 return (ret);
1351 1338 }
1352 1339 /* End of driver configuration functions */
1353 1340
1354 1341 static int
1355 1342 tpm_resume(tpm_state_t *tpm)
1356 1343 {
1357 1344 mutex_enter(&tpm->pm_mutex);
1358 1345 if (!tpm->suspended) {
1359 1346 mutex_exit(&tpm->pm_mutex);
1360 1347 return (DDI_FAILURE);
1361 1348 }
1362 1349 tpm->suspended = 0;
1363 1350 cv_broadcast(&tpm->suspend_cv);
1364 1351 mutex_exit(&tpm->pm_mutex);
1365 1352
1366 1353 return (DDI_SUCCESS);
1367 1354 }
1368 1355
1369 1356 #ifdef sun4v
1370 1357 static uint64_t hsvc_tpm_minor = 0;
1371 1358 static hsvc_info_t hsvc_tpm = {
1372 1359 HSVC_REV_1, NULL, HSVC_GROUP_TPM, 1, 0, NULL
1373 1360 };
1374 1361 #endif
1375 1362
1376 1363 /*
1377 1364 * Sun DDI/DDK entry points
1378 1365 */
1379 1366 static int
1380 1367 tpm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1381 1368 {
1382 1369 int ret;
1383 1370 int instance;
1384 1371 #ifndef sun4v
1385 1372 int idx, nregs;
1386 1373 #endif
1387 1374 char *myname = "tpm_attach";
1388 1375 tpm_state_t *tpm = NULL;
1389 1376
1390 1377 ASSERT(dip != NULL);
1391 1378
1392 1379 instance = ddi_get_instance(dip);
1393 1380 if (instance < 0)
1394 1381 return (DDI_FAILURE);
1395 1382
1396 1383 /* Nothing out of ordinary here */
1397 1384 switch (cmd) {
1398 1385 case DDI_ATTACH:
1399 1386 if (ddi_soft_state_zalloc(statep, instance) == DDI_SUCCESS) {
1400 1387 tpm = ddi_get_soft_state(statep, instance);
1401 1388 if (tpm == NULL) {
1402 1389 #ifdef DEBUG
1403 1390 cmn_err(CE_WARN,
1404 1391 "!%s: cannot get state information.",
1405 1392 myname);
1406 1393 #endif
1407 1394 return (DDI_FAILURE);
1408 1395 }
1409 1396 tpm->dip = dip;
1410 1397 } else {
1411 1398 #ifdef DEBUG
1412 1399 cmn_err(CE_WARN,
1413 1400 "!%s: cannot allocate state information.",
1414 1401 myname);
1415 1402 #endif
1416 1403 return (DDI_FAILURE);
1417 1404 }
1418 1405 break;
1419 1406 case DDI_RESUME:
1420 1407 tpm = ddi_get_soft_state(statep, instance);
1421 1408 if (tpm == NULL) {
1422 1409 #ifdef DEBUG
1423 1410 cmn_err(CE_WARN, "!%s: cannot get state information.",
1424 1411 myname);
1425 1412 #endif
1426 1413 return (DDI_FAILURE);
1427 1414 }
1428 1415 return (tpm_resume(tpm));
1429 1416 default:
1430 1417 #ifdef DEBUG
1431 1418 cmn_err(CE_WARN, "!%s: cmd %d is not implemented", myname, cmd);
1432 1419 #endif
1433 1420 ret = DDI_FAILURE;
1434 1421 goto FAIL;
1435 1422 }
1436 1423
1437 1424 /* Zeroize the flag, which is used to keep track of what is allocated */
1438 1425 tpm->flags = 0;
1439 1426
1440 1427 #ifdef sun4v
1441 1428 ret = hsvc_register(&hsvc_tpm, &hsvc_tpm_minor);
1442 1429 if (ret != 0) {
1443 1430 cmn_err(CE_WARN, "!%s: failed to register with "
1444 1431 "hypervisor: 0x%0x", myname, ret);
1445 1432 goto FAIL;
1446 1433 }
1447 1434 tpm->flags |= TPM_HSVC_REGISTERED;
1448 1435 #else
1449 1436 tpm->accattr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1450 1437 tpm->accattr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
1451 1438 tpm->accattr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1452 1439
1453 1440 idx = 0;
1454 1441 ret = ddi_dev_nregs(tpm->dip, &nregs);
1455 1442 if (ret != DDI_SUCCESS)
1456 1443 goto FAIL;
1457 1444
1458 1445 /*
1459 1446 * TPM vendors put the TPM registers in different
1460 1447 * slots in their register lists. They are not always
1461 1448 * the 1st set of registers, for instance.
1462 1449 * Loop until we find the set that matches the expected
1463 1450 * register size (0x5000).
1464 1451 */
1465 1452 for (idx = 0; idx < nregs; idx++) {
1466 1453 off_t regsize;
1467 1454
1468 1455 if ((ret = ddi_dev_regsize(tpm->dip, idx, ®size)) !=
1469 1456 DDI_SUCCESS)
1470 1457 goto FAIL;
1471 1458 /* The TIS spec says the TPM registers must be 0x5000 bytes */
1472 1459 if (regsize == 0x5000)
1473 1460 break;
1474 1461 }
1475 1462 if (idx == nregs) {
1476 1463 ret = DDI_FAILURE;
1477 1464 goto FAIL;
1478 1465 }
1479 1466
1480 1467 ret = ddi_regs_map_setup(tpm->dip, idx, (caddr_t *)&tpm->addr,
1481 1468 (offset_t)0, (offset_t)0x5000,
1482 1469 &tpm->accattr, &tpm->handle);
1483 1470
1484 1471 if (ret != DDI_SUCCESS) {
1485 1472 goto FAIL;
1486 1473 }
1487 1474 tpm->flags |= TPM_DIDREGSMAP;
1488 1475 #endif
1489 1476 /* Enable TPM device according to the TIS specification */
1490 1477 ret = tis_init(tpm);
1491 1478 if (ret != DDI_SUCCESS) {
1492 1479 #ifdef DEBUG
1493 1480 cmn_err(CE_WARN, "!%s: tis_init() failed with error %d",
1494 1481 myname, ret);
1495 1482 #endif
1496 1483
1497 1484 /* We need to clean up the ddi_regs_map_setup call */
1498 1485 if (tpm->flags & TPM_DIDREGSMAP) {
1499 1486 ddi_regs_map_free(&tpm->handle);
1500 1487 tpm->handle = NULL;
1501 1488 tpm->flags &= ~TPM_DIDREGSMAP;
1502 1489 }
1503 1490 goto FAIL;
1504 1491 }
1505 1492
1506 1493 /* Initialize the inter-process lock */
1507 1494 mutex_init(&tpm->dev_lock, NULL, MUTEX_DRIVER, NULL);
1508 1495 mutex_init(&tpm->pm_mutex, NULL, MUTEX_DRIVER, NULL);
1509 1496 cv_init(&tpm->suspend_cv, NULL, CV_DRIVER, NULL);
1510 1497
1511 1498 /* Set the suspend/resume property */
1512 1499 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
1513 1500 "pm-hardware-state", "needs-suspend-resume");
1514 1501
1515 1502 mutex_enter(&tpm->pm_mutex);
1516 1503 tpm->suspended = 0;
1517 1504 mutex_exit(&tpm->pm_mutex);
1518 1505
1519 1506 tpm->flags |= TPM_DID_MUTEX;
1520 1507
1521 1508 /* Initialize the buffer and the lock associated with it */
1522 1509 tpm->bufsize = TPM_IO_BUF_SIZE;
1523 1510 tpm->iobuf = kmem_zalloc((sizeof (uint8_t))*(tpm->bufsize), KM_SLEEP);
1524 1511 tpm->flags |= TPM_DID_IO_ALLOC;
1525 1512
1526 1513 mutex_init(&tpm->iobuf_lock, NULL, MUTEX_DRIVER, NULL);
1527 1514 tpm->flags |= TPM_DID_IO_MUTEX;
1528 1515
1529 1516 cv_init(&tpm->iobuf_cv, NULL, CV_DRIVER, NULL);
1530 1517 tpm->flags |= TPM_DID_IO_CV;
1531 1518
1532 1519 /* Create minor node */
1533 1520 ret = ddi_create_minor_node(dip, "tpm", S_IFCHR, ddi_get_instance(dip),
1534 1521 DDI_PSEUDO, 0);
1535 1522 if (ret != DDI_SUCCESS) {
1536 1523 #ifdef DEBUG
1537 1524 cmn_err(CE_WARN, "!%s: ddi_create_minor_node failed", myname);
1538 1525 #endif
1539 1526 goto FAIL;
1540 1527 }
1541 1528 tpm->flags |= TPM_DIDMINOR;
1542 1529
1543 1530 #ifdef KCF_TPM_RNG_PROVIDER
1544 1531 /* register RNG with kcf */
1545 1532 if (tpmrng_register(tpm) != DDI_SUCCESS)
1546 1533 cmn_err(CE_WARN, "!%s: tpm RNG failed to register with kcf",
1547 1534 myname);
1548 1535 #endif
1549 1536
1550 1537 return (DDI_SUCCESS);
1551 1538 FAIL:
1552 1539 if (tpm != NULL) {
1553 1540 tpm_cleanup(dip, tpm);
1554 1541 ddi_soft_state_free(statep, instance);
1555 1542 tpm = NULL;
1556 1543 }
1557 1544
1558 1545 return (DDI_FAILURE);
1559 1546 }
1560 1547
1561 1548 /*
1562 1549 * Called by tpm_detach and tpm_attach (only on failure)
1563 1550 * Free up the resources that are allocated
1564 1551 */
1565 1552 static void
1566 1553 tpm_cleanup(dev_info_t *dip, tpm_state_t *tpm)
1567 1554 {
1568 1555 if (tpm == NULL)
1569 1556 return;
1570 1557
1571 1558 #ifdef KCF_TPM_RNG_PROVIDER
1572 1559 (void) tpmrng_unregister(tpm);
1573 1560 #endif
1574 1561
1575 1562 #ifdef sun4v
1576 1563 if (tpm->flags & TPM_HSVC_REGISTERED) {
1577 1564 (void) hsvc_unregister(&hsvc_tpm);
1578 1565 tpm->flags &= ~(TPM_HSVC_REGISTERED);
1579 1566 }
1580 1567 #endif
1581 1568 if (tpm->flags & TPM_DID_MUTEX) {
1582 1569 mutex_destroy(&tpm->dev_lock);
1583 1570 mutex_destroy(&tpm->pm_mutex);
1584 1571 cv_destroy(&tpm->suspend_cv);
1585 1572 tpm->flags &= ~(TPM_DID_MUTEX);
1586 1573 }
1587 1574 if (tpm->flags & TPM_DID_IO_ALLOC) {
1588 1575 ASSERT(tpm->iobuf != NULL);
1589 1576 kmem_free(tpm->iobuf, (sizeof (uint8_t))*(tpm->bufsize));
1590 1577 tpm->flags &= ~(TPM_DID_IO_ALLOC);
1591 1578 }
1592 1579 if (tpm->flags & TPM_DID_IO_MUTEX) {
1593 1580 mutex_destroy(&tpm->iobuf_lock);
1594 1581 tpm->flags &= ~(TPM_DID_IO_MUTEX);
1595 1582 }
1596 1583 if (tpm->flags & TPM_DID_IO_CV) {
1597 1584 cv_destroy(&tpm->iobuf_cv);
1598 1585 tpm->flags &= ~(TPM_DID_IO_CV);
1599 1586 }
1600 1587 if (tpm->flags & TPM_DIDREGSMAP) {
1601 1588 /* Free the mapped addresses */
1602 1589 if (tpm->handle != NULL)
1603 1590 ddi_regs_map_free(&tpm->handle);
1604 1591 tpm->flags &= ~(TPM_DIDREGSMAP);
1605 1592 }
1606 1593 if (tpm->flags & TPM_DIDMINOR) {
1607 1594 /* Remove minor node */
1608 1595 ddi_remove_minor_node(dip, NULL);
1609 1596 tpm->flags &= ~(TPM_DIDMINOR);
1610 1597 }
1611 1598 }
1612 1599
1613 1600 static int
1614 1601 tpm_suspend(tpm_state_t *tpm)
1615 1602 {
1616 1603 if (tpm == NULL)
1617 1604 return (DDI_FAILURE);
1618 1605 mutex_enter(&tpm->pm_mutex);
1619 1606 if (tpm->suspended) {
1620 1607 mutex_exit(&tpm->pm_mutex);
1621 1608 return (DDI_SUCCESS);
1622 1609 }
1623 1610 tpm->suspended = 1;
1624 1611 mutex_exit(&tpm->pm_mutex);
1625 1612
1626 1613 return (DDI_SUCCESS);
1627 1614 }
1628 1615
1629 1616 static int
1630 1617 tpm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1631 1618 {
1632 1619 char *myname = "tpm_detach";
1633 1620 int instance;
1634 1621 tpm_state_t *tpm;
1635 1622
1636 1623 ASSERT(dip != NULL);
1637 1624
1638 1625 instance = ddi_get_instance(dip);
1639 1626 if (instance < 0)
1640 1627 return (DDI_FAILURE);
1641 1628
1642 1629 if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1643 1630 #ifdef DEBUG
1644 1631 cmn_err(CE_WARN, "!%s: stored pointer to tpm state is NULL",
1645 1632 myname);
1646 1633 #endif
1647 1634 return (ENXIO);
1648 1635 }
1649 1636
1650 1637 switch (cmd) {
1651 1638 case DDI_DETACH:
1652 1639 /* Body is after the switch stmt */
1653 1640 break;
1654 1641 case DDI_SUSPEND:
1655 1642 return (tpm_suspend(tpm));
1656 1643 default:
1657 1644 #ifdef DEBUG
1658 1645 cmn_err(CE_WARN, "!%s: case %d not implemented", myname, cmd);
1659 1646 #endif
1660 1647 return (DDI_FAILURE);
1661 1648 }
1662 1649
1663 1650 /* Since we are freeing tpm structure, we need to gain the lock */
1664 1651 tpm_cleanup(dip, tpm);
1665 1652
1666 1653 /* Free the soft state */
1667 1654 ddi_soft_state_free(statep, instance);
1668 1655 tpm = NULL;
1669 1656
1670 1657 return (DDI_SUCCESS);
1671 1658 }
1672 1659
1673 1660 /*ARGSUSED*/
1674 1661 static int
1675 1662 tpm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
1676 1663 {
1677 1664 char *myname = "tpm_getinfo";
1678 1665 int instance;
1679 1666 tpm_state_t *tpm;
1680 1667
1681 1668 instance = ddi_get_instance(dip);
1682 1669 if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1683 1670 #ifdef DEBUG
1684 1671 cmn_err(CE_WARN, "!%s: stored pointer to tpm state is NULL",
1685 1672 myname);
1686 1673 #endif
1687 1674 return (DDI_FAILURE);
1688 1675 }
1689 1676
1690 1677 switch (cmd) {
1691 1678 case DDI_INFO_DEVT2DEVINFO:
1692 1679 *resultp = tpm->dip;
1693 1680 break;
1694 1681 case DDI_INFO_DEVT2INSTANCE:
1695 1682 *resultp = 0;
1696 1683 break;
1697 1684 default:
1698 1685 #ifdef DEBUG
1699 1686 cmn_err(CE_WARN, "!%s: cmd %d is not implemented", myname, cmd);
1700 1687 #endif
1701 1688 return (DDI_FAILURE);
1702 1689 }
1703 1690 return (DDI_SUCCESS);
1704 1691 }
1705 1692
1706 1693 /*
1707 1694 * Driver entry points
1708 1695 */
1709 1696
1710 1697 /*ARGSUSED*/
1711 1698 static int
1712 1699 tpm_open(dev_t *devp, int flag, int otyp, cred_t *cred)
1713 1700 {
1714 1701 char *myname = "tpm_open";
1715 1702 int instance;
1716 1703 tpm_state_t *tpm;
1717 1704
1718 1705 ASSERT(devp != NULL);
1719 1706
1720 1707 instance = getminor(*devp);
1721 1708 if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1722 1709 #ifdef DEBUG
1723 1710 cmn_err(CE_WARN, "!%s: stored pointer to tpm state is NULL",
1724 1711 myname);
1725 1712 #endif
1726 1713 return (ENXIO);
1727 1714 }
1728 1715 if (otyp != OTYP_CHR) {
1729 1716 #ifdef DEBUG
1730 1717 cmn_err(CE_WARN, "!%s: otyp(%d) != OTYP_CHR(%d)",
1731 1718 myname, otyp, OTYP_CHR);
1732 1719 #endif
1733 1720 return (EINVAL);
1734 1721 }
1735 1722 TPM_EXCLUSIVE_LOCK(tpm);
1736 1723
1737 1724 mutex_enter(&tpm->dev_lock);
1738 1725 if (tpm->dev_held) {
1739 1726 #ifdef DEBUG
1740 1727 cmn_err(CE_WARN, "!%s: the device is already being used",
1741 1728 myname);
1742 1729 #endif
1743 1730 mutex_exit(&tpm->dev_lock);
1744 1731 return (EBUSY);
1745 1732 }
1746 1733
1747 1734 /* The device is free so mark it busy */
1748 1735 tpm->dev_held = 1;
1749 1736 mutex_exit(&tpm->dev_lock);
1750 1737
1751 1738 return (0);
1752 1739 }
1753 1740
1754 1741 /*ARGSUSED*/
1755 1742 static int
1756 1743 tpm_close(dev_t dev, int flag, int otyp, cred_t *cred)
1757 1744 {
1758 1745 char *myname = "tpm_close";
1759 1746 int instance;
1760 1747 tpm_state_t *tpm;
1761 1748
1762 1749 instance = getminor(dev);
1763 1750 if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1764 1751 #ifdef DEBUG
1765 1752 cmn_err(CE_WARN, "!%s: stored pointer to tpm state is NULL",
1766 1753 myname);
1767 1754 #endif
1768 1755 return (ENXIO);
1769 1756 }
1770 1757 if (otyp != OTYP_CHR) {
1771 1758 #ifdef DEBUG
1772 1759 cmn_err(CE_WARN, "!%s: otyp(%d) != OTYP_CHR(%d)",
1773 1760 myname, otyp, OTYP_CHR);
1774 1761 #endif
1775 1762 return (EINVAL);
1776 1763 }
1777 1764 TPM_EXCLUSIVE_LOCK(tpm);
1778 1765
1779 1766 ASSERT(tpm->dev_held);
1780 1767
1781 1768 mutex_enter(&tpm->dev_lock);
1782 1769 ASSERT(mutex_owned(&tpm->dev_lock));
1783 1770 tpm->dev_held = 0;
1784 1771 mutex_exit(&tpm->dev_lock);
1785 1772
1786 1773 return (0);
1787 1774 }
1788 1775
1789 1776 /*ARGSUSED*/
1790 1777 static int
1791 1778 tpm_read(dev_t dev, struct uio *uiop, cred_t *credp)
1792 1779 {
1793 1780 int ret;
1794 1781 uint32_t size;
1795 1782 char *myname = "tpm_read";
1796 1783 int instance;
1797 1784 tpm_state_t *tpm;
1798 1785
1799 1786 instance = getminor(dev);
1800 1787 if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1801 1788 #ifdef DEBUG
1802 1789 cmn_err(CE_WARN, "!%s: stored pointer to tpm state is NULL",
1803 1790 myname);
1804 1791 #endif
1805 1792 return (ENXIO);
1806 1793 }
1807 1794 if (uiop == NULL) {
1808 1795 #ifdef DEBUG
1809 1796 cmn_err(CE_WARN, "!%s: passed in uiop is NULL", myname);
1810 1797 #endif
1811 1798 return (EFAULT);
1812 1799 }
1813 1800
1814 1801 TPM_EXCLUSIVE_LOCK(tpm);
1815 1802
1816 1803 /* Receive the data after requiring the lock */
1817 1804 ret = tpm_io_lock(tpm);
1818 1805
1819 1806 /* Timeout reached */
1820 1807 if (ret)
1821 1808 return (ret);
1822 1809
1823 1810 if (uiop->uio_resid > tpm->bufsize) {
1824 1811 #ifdef DEBUG
1825 1812 cmn_err(CE_WARN, "!%s: read_in data is bigger "
1826 1813 "than tpm->bufsize:read in:%d, bufsiz:%d",
1827 1814 myname, (int)uiop->uio_resid, (int)tpm->bufsize);
1828 1815 #endif
1829 1816 ret = EIO;
1830 1817 goto OUT;
1831 1818 }
1832 1819
1833 1820 ret = tis_recv_data(tpm, tpm->iobuf, tpm->bufsize);
1834 1821 if (ret < TPM_HEADER_SIZE) {
1835 1822 #ifdef DEBUG
1836 1823 cmn_err(CE_WARN, "!%s: tis_recv_data returned error", myname);
1837 1824 #endif
1838 1825 ret = EIO;
1839 1826 goto OUT;
1840 1827 }
1841 1828
1842 1829 size = load32(tpm->iobuf, 2);
1843 1830 if (ret != size) {
1844 1831 #ifdef DEBUG
1845 1832 cmn_err(CE_WARN, "!%s: tis_recv_data:"
1846 1833 "expected size=%d, actually read=%d",
1847 1834 myname, size, ret);
1848 1835 #endif
1849 1836 ret = EIO;
1850 1837 goto OUT;
1851 1838 }
1852 1839
1853 1840 /* Send the buffer from the kernel to the userspace */
1854 1841 ret = uiomove(tpm->iobuf, size, UIO_READ, uiop);
1855 1842 if (ret) {
1856 1843 #ifdef DEBUG
1857 1844 cmn_err(CE_WARN, "!%s: uiomove returned error", myname);
1858 1845 #endif
1859 1846 goto OUT;
1860 1847 }
1861 1848
1862 1849 /* Zeroize the buffer... */
1863 1850 bzero(tpm->iobuf, tpm->bufsize);
1864 1851 ret = DDI_SUCCESS;
1865 1852 OUT:
1866 1853 /* We are done now: wake up the waiting threads */
1867 1854 tpm_unlock(tpm);
1868 1855
1869 1856 return (ret);
1870 1857 }
1871 1858
1872 1859 /*ARGSUSED*/
1873 1860 static int
1874 1861 tpm_write(dev_t dev, struct uio *uiop, cred_t *credp)
1875 1862 {
1876 1863 int ret;
1877 1864 size_t len;
1878 1865 uint32_t size;
1879 1866 char *myname = "tpm_write";
1880 1867 int instance;
1881 1868 tpm_state_t *tpm;
1882 1869
1883 1870 instance = getminor(dev);
1884 1871 if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1885 1872 #ifdef DEBUG
1886 1873 cmn_err(CE_WARN, "!%s: stored pointer to tpm state is NULL",
1887 1874 myname);
1888 1875 #endif
1889 1876 return (ENXIO);
1890 1877 }
1891 1878
1892 1879 if (uiop == NULL) {
1893 1880 #ifdef DEBUG
1894 1881 cmn_err(CE_WARN, "!%s: passed in uiop is NULL", myname);
1895 1882 #endif
1896 1883 return (EFAULT);
1897 1884 }
1898 1885
1899 1886 TPM_EXCLUSIVE_LOCK(tpm);
1900 1887
1901 1888 len = uiop->uio_resid;
1902 1889 if (len == 0) {
1903 1890 #ifdef DEBUG
1904 1891 cmn_err(CE_WARN, "!%s: requested read of len 0", myname);
1905 1892 #endif
1906 1893 return (0);
1907 1894 }
1908 1895
1909 1896 /* Get the lock for using iobuf */
1910 1897 ret = tpm_io_lock(tpm);
1911 1898 /* Timeout Reached */
1912 1899 if (ret)
1913 1900 return (ret);
1914 1901
1915 1902 /* Copy the header and parse the structure to find out the size... */
1916 1903 ret = uiomove(tpm->iobuf, TPM_HEADER_SIZE, UIO_WRITE, uiop);
1917 1904 if (ret) {
1918 1905 #ifdef DEBUG
1919 1906 cmn_err(CE_WARN, "!%s: uiomove returned error"
1920 1907 "while getting the the header",
1921 1908 myname);
1922 1909 #endif
1923 1910 goto OUT;
1924 1911 }
1925 1912
1926 1913 /* Get the buffersize from the command buffer structure */
1927 1914 size = load32(tpm->iobuf, TPM_PARAMSIZE_OFFSET);
1928 1915
1929 1916 /* Copy the command to the contiguous buffer */
1930 1917 if (size > tpm->bufsize) {
1931 1918 #ifdef DEBUG
1932 1919 cmn_err(CE_WARN, "!%s: size %d is greater than "
1933 1920 "the tpm input buffer size %d",
1934 1921 myname, (int)size, (int)tpm->bufsize);
1935 1922 #endif
1936 1923 ret = ENXIO;
1937 1924 goto OUT;
1938 1925 }
1939 1926
1940 1927 /* Copy the buffer from the userspace to kernel */
1941 1928 ret = uiomove(tpm->iobuf+TPM_HEADER_SIZE, size-TPM_HEADER_SIZE,
1942 1929 UIO_WRITE, uiop);
1943 1930
1944 1931 if (ret) {
1945 1932 #ifdef DEBUG
1946 1933 cmn_err(CE_WARN, "!%s: uiomove returned error"
1947 1934 "while getting the rest of the command", myname);
1948 1935 #endif
1949 1936 goto OUT;
1950 1937 }
1951 1938
1952 1939 /* Send the command */
1953 1940 ret = tis_send_data(tpm, tpm->iobuf, size);
1954 1941 if (ret != DDI_SUCCESS) {
1955 1942 #ifdef DEBUG
1956 1943 cmn_err(CE_WARN, "!%s: tis_send_data returned error", myname);
1957 1944 #endif
1958 1945 ret = EFAULT;
1959 1946 goto OUT;
1960 1947 }
1961 1948
1962 1949 /* Zeroize the buffer... */
1963 1950 bzero(tpm->iobuf, tpm->bufsize);
1964 1951 ret = DDI_SUCCESS;
1965 1952 OUT:
1966 1953 tpm_unlock(tpm);
1967 1954 return (ret);
1968 1955 }
1969 1956
1970 1957 /*
1971 1958 * This is to deal with the contentions for the iobuf
1972 1959 */
1973 1960 static inline int
1974 1961 tpm_io_lock(tpm_state_t *tpm)
1975 1962 {
1976 1963 int ret;
1977 1964 clock_t timeout;
1978 1965
1979 1966 mutex_enter(&tpm->iobuf_lock);
1980 1967 ASSERT(mutex_owned(&tpm->iobuf_lock));
1981 1968
1982 1969 timeout = ddi_get_lbolt() + drv_usectohz(TPM_IO_TIMEOUT);
1983 1970
1984 1971 /* Wait until the iobuf becomes free with the timeout */
1985 1972 while (tpm->iobuf_inuse) {
1986 1973 ret = cv_timedwait(&tpm->iobuf_cv, &tpm->iobuf_lock, timeout);
1987 1974 if (ret <= 0) {
1988 1975 /* Timeout reached */
1989 1976 mutex_exit(&tpm->iobuf_lock);
1990 1977 #ifdef DEBUG
1991 1978 cmn_err(CE_WARN, "!tpm_io_lock:iorequest timed out");
1992 1979 #endif
1993 1980 return (ETIME);
1994 1981 }
1995 1982 }
1996 1983 tpm->iobuf_inuse = 1;
1997 1984 mutex_exit(&tpm->iobuf_lock);
1998 1985 return (0);
1999 1986 }
2000 1987
2001 1988 /*
2002 1989 * This is to deal with the contentions for the iobuf
2003 1990 */
2004 1991 static inline void
2005 1992 tpm_unlock(tpm_state_t *tpm)
2006 1993 {
2007 1994 /* Wake up the waiting threads */
2008 1995 mutex_enter(&tpm->iobuf_lock);
2009 1996 ASSERT(tpm->iobuf_inuse == 1 && mutex_owned(&tpm->iobuf_lock));
2010 1997 tpm->iobuf_inuse = 0;
2011 1998 cv_broadcast(&tpm->iobuf_cv);
2012 1999 mutex_exit(&tpm->iobuf_lock);
2013 2000 }
2014 2001
2015 2002 #ifdef KCF_TPM_RNG_PROVIDER
2016 2003 /*
2017 2004 * Random number generator entry points
2018 2005 */
2019 2006 static void
2020 2007 strncpy_spacepad(uchar_t *s1, char *s2, int n)
2021 2008 {
2022 2009 int s2len = strlen(s2);
2023 2010 (void) strncpy((char *)s1, s2, n);
2024 2011 if (s2len < n)
2025 2012 (void) memset(s1 + s2len, ' ', n - s2len);
2026 2013 }
2027 2014
2028 2015 /*ARGSUSED*/
2029 2016 static int
2030 2017 tpmrng_ext_info(crypto_provider_handle_t prov,
2031 2018 crypto_provider_ext_info_t *ext_info,
2032 2019 crypto_req_handle_t cfreq)
2033 2020 {
2034 2021 tpm_state_t *tpm = (tpm_state_t *)prov;
2035 2022 char buf[64];
2036 2023
2037 2024 if (tpm == NULL)
2038 2025 return (DDI_FAILURE);
2039 2026
2040 2027 strncpy_spacepad(ext_info->ei_manufacturerID,
2041 2028 (char *)tpm->vers_info.tpmVendorID,
2042 2029 sizeof (ext_info->ei_manufacturerID));
2043 2030
2044 2031 strncpy_spacepad(ext_info->ei_model, "0",
2045 2032 sizeof (ext_info->ei_model));
2046 2033 strncpy_spacepad(ext_info->ei_serial_number, "0",
2047 2034 sizeof (ext_info->ei_serial_number));
2048 2035
2049 2036 ext_info->ei_flags = CRYPTO_EXTF_RNG | CRYPTO_EXTF_SO_PIN_LOCKED;
2050 2037 ext_info->ei_max_session_count = CRYPTO_EFFECTIVELY_INFINITE;
2051 2038 ext_info->ei_max_pin_len = 0;
2052 2039 ext_info->ei_min_pin_len = 0;
2053 2040 ext_info->ei_total_public_memory = CRYPTO_UNAVAILABLE_INFO;
2054 2041 ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
2055 2042 ext_info->ei_total_private_memory = CRYPTO_UNAVAILABLE_INFO;
2056 2043 ext_info->ei_free_public_memory = CRYPTO_UNAVAILABLE_INFO;
2057 2044 ext_info->ei_time[0] = 0;
2058 2045
2059 2046 ext_info->ei_hardware_version.cv_major = tpm->vers_info.version.major;
2060 2047 ext_info->ei_hardware_version.cv_minor = tpm->vers_info.version.minor;
2061 2048 ext_info->ei_firmware_version.cv_major =
2062 2049 tpm->vers_info.version.revMajor;
2063 2050 ext_info->ei_firmware_version.cv_minor =
2064 2051 tpm->vers_info.version.revMinor;
2065 2052
2066 2053 (void) snprintf(buf, sizeof (buf), "tpmrng TPM RNG");
2067 2054
2068 2055 strncpy_spacepad(ext_info->ei_label, buf,
2069 2056 sizeof (ext_info->ei_label));
2070 2057 #undef BUFSZ
2071 2058 return (CRYPTO_SUCCESS);
2072 2059
2073 2060 }
2074 2061
2075 2062 static int
2076 2063 tpmrng_register(tpm_state_t *tpm)
2077 2064 {
2078 2065 int ret;
2079 2066 char ID[64];
2080 2067 crypto_mech_name_t *rngmech;
2081 2068
2082 2069 ASSERT(tpm != NULL);
2083 2070
2084 2071 (void) snprintf(ID, sizeof (ID), "tpmrng %s", IDENT_TPMRNG);
2085 2072
2086 2073 tpmrng_prov_info.pi_provider_description = ID;
2087 2074 tpmrng_prov_info.pi_provider_dev.pd_hw = tpm->dip;
2088 2075 tpmrng_prov_info.pi_provider_handle = tpm;
2089 2076
2090 2077 ret = crypto_register_provider(&tpmrng_prov_info, &tpm->n_prov);
2091 2078 if (ret != CRYPTO_SUCCESS) {
2092 2079 tpm->n_prov = NULL;
2093 2080 return (DDI_FAILURE);
2094 2081 }
2095 2082
2096 2083 crypto_provider_notification(tpm->n_prov, CRYPTO_PROVIDER_READY);
2097 2084
2098 2085 rngmech = kmem_zalloc(strlen("random") + 1, KM_SLEEP);
2099 2086 (void) memcpy(rngmech, "random", 6);
2100 2087 ret = crypto_load_dev_disabled("tpm", ddi_get_instance(tpm->dip),
2101 2088 1, rngmech);
2102 2089 #ifdef DEBUG
2103 2090 if (ret != CRYPTO_SUCCESS)
2104 2091 cmn_err(CE_WARN, "!crypto_load_dev_disabled failed (%d)", ret);
2105 2092 #endif
2106 2093 return (DDI_SUCCESS);
2107 2094 }
2108 2095
2109 2096 static int
2110 2097 tpmrng_unregister(tpm_state_t *tpm)
2111 2098 {
2112 2099 int ret;
2113 2100 ASSERT(tpm != NULL);
2114 2101 if (tpm->n_prov) {
2115 2102 ret = crypto_unregister_provider(tpm->n_prov);
2116 2103 tpm->n_prov = NULL;
2117 2104 if (ret != CRYPTO_SUCCESS)
2118 2105 return (DDI_FAILURE);
2119 2106 }
2120 2107 return (DDI_SUCCESS);
2121 2108 }
2122 2109
2123 2110 /*ARGSUSED*/
2124 2111 static void
2125 2112 tpmrng_provider_status(crypto_provider_handle_t provider, uint_t *status)
2126 2113 {
2127 2114 *status = CRYPTO_PROVIDER_READY;
2128 2115 }
2129 2116
2130 2117 /*ARGSUSED*/
2131 2118 static int
2132 2119 tpmrng_seed_random(crypto_provider_handle_t provider, crypto_session_id_t sid,
2133 2120 uchar_t *buf, size_t len, uint_t entropy_est, uint32_t flags,
2134 2121 crypto_req_handle_t req)
2135 2122 {
2136 2123 int ret;
2137 2124 tpm_state_t *tpm;
2138 2125 uint32_t len32;
2139 2126 /* Max length of seed is 256 bytes, add 14 for header. */
2140 2127 uint8_t cmdbuf[270] = {
2141 2128 0, 193, /* TPM_TAG_RQU COMMAND */
2142 2129 0, 0, 0, 0x0A, /* paramsize in bytes */
2143 2130 0, 0, 0, TPM_ORD_StirRandom,
2144 2131 0, 0, 0, 0 /* number of input bytes (< 256) */
2145 2132 };
2146 2133 uint32_t buflen;
2147 2134
2148 2135 if (len == 0 || len > 255 || buf == NULL)
2149 2136 return (CRYPTO_ARGUMENTS_BAD);
2150 2137
2151 2138 tpm = (tpm_state_t *)provider;
2152 2139 if (tpm == NULL)
2153 2140 return (CRYPTO_INVALID_CONTEXT);
2154 2141
2155 2142 /* Acquire lock for exclusive use of TPM */
2156 2143 TPM_EXCLUSIVE_LOCK(tpm);
2157 2144
2158 2145 ret = tpm_io_lock(tpm);
2159 2146 /* Timeout reached */
2160 2147 if (ret)
2161 2148 return (CRYPTO_BUSY);
2162 2149
2163 2150 /* TPM only handles 32 bit length, so truncate if too big. */
2164 2151 len32 = (uint32_t)len;
2165 2152 buflen = len32 + 14;
2166 2153
2167 2154 /* The length must be in network order */
2168 2155 buflen = htonl(buflen);
2169 2156 bcopy(&buflen, cmdbuf + 2, sizeof (uint32_t));
2170 2157
2171 2158 /* Convert it back */
2172 2159 buflen = ntohl(buflen);
2173 2160
2174 2161 /* length must be in network order */
2175 2162 len32 = htonl(len32);
2176 2163 bcopy(&len32, cmdbuf + 10, sizeof (uint32_t));
2177 2164
2178 2165 /* convert it back */
2179 2166 len32 = ntohl(len32);
2180 2167
2181 2168 bcopy(buf, cmdbuf + 14, len32);
2182 2169
2183 2170 ret = itpm_command(tpm, cmdbuf, buflen);
2184 2171 tpm_unlock(tpm);
2185 2172
2186 2173 if (ret != DDI_SUCCESS) {
2187 2174 #ifdef DEBUG
2188 2175 cmn_err(CE_WARN, "!tpmrng_seed_random failed");
2189 2176 #endif
2190 2177 return (CRYPTO_FAILED);
2191 2178 }
2192 2179
2193 2180 return (CRYPTO_SUCCESS);
2194 2181 }
2195 2182
2196 2183 /* ARGSUSED */
2197 2184 static int
2198 2185 tpmrng_generate_random(crypto_provider_handle_t provider,
2199 2186 crypto_session_id_t sid, uchar_t *buf, size_t len, crypto_req_handle_t req)
2200 2187 {
2201 2188 int ret;
2202 2189 tpm_state_t *tpm;
2203 2190 uint8_t hdr[14] = {
2204 2191 0, 193, /* TPM_TAG_RQU COMMAND */
2205 2192 0, 0, 0, 14, /* paramsize in bytes */
2206 2193 0, 0, 0, TPM_ORD_GetRandom,
2207 2194 0, 0, 0, 0
2208 2195 };
2209 2196 uint8_t *cmdbuf = NULL;
2210 2197 uint32_t len32 = (uint32_t)len;
2211 2198 uint32_t buflen = len32 + sizeof (hdr);
2212 2199
2213 2200 if (len == 0 || buf == NULL)
2214 2201 return (CRYPTO_ARGUMENTS_BAD);
2215 2202
2216 2203 tpm = (tpm_state_t *)provider;
2217 2204 if (tpm == NULL)
2218 2205 return (CRYPTO_INVALID_CONTEXT);
2219 2206
2220 2207 TPM_EXCLUSIVE_LOCK(tpm);
2221 2208
2222 2209 ret = tpm_io_lock(tpm);
2223 2210 /* Timeout reached */
2224 2211 if (ret)
2225 2212 return (CRYPTO_BUSY);
2226 2213
2227 2214 cmdbuf = kmem_zalloc(buflen, KM_SLEEP);
2228 2215 bcopy(hdr, cmdbuf, sizeof (hdr));
2229 2216
2230 2217 /* Length is written in network byte order */
2231 2218 len32 = htonl(len32);
2232 2219 bcopy(&len32, cmdbuf + 10, sizeof (uint32_t));
2233 2220
2234 2221 ret = itpm_command(tpm, cmdbuf, buflen);
2235 2222 if (ret != DDI_SUCCESS) {
2236 2223 #ifdef DEBUG
2237 2224 cmn_err(CE_WARN, "!tpmrng_generate_random failed");
2238 2225 #endif
2239 2226 kmem_free(cmdbuf, buflen);
2240 2227 tpm_unlock(tpm);
2241 2228 return (CRYPTO_FAILED);
2242 2229 }
2243 2230
2244 2231 /* Find out how many bytes were really returned */
2245 2232 len32 = load32(cmdbuf, 10);
2246 2233
2247 2234 /* Copy the random bytes back to the callers buffer */
2248 2235 bcopy(cmdbuf + 14, buf, len32);
2249 2236
2250 2237 kmem_free(cmdbuf, buflen);
2251 2238 tpm_unlock(tpm);
2252 2239
2253 2240 return (CRYPTO_SUCCESS);
2254 2241 }
2255 2242 #endif /* KCF_TPM_RNG_PROVIDER */
↓ open down ↓ |
1968 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX