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