xref: /illumos-gate/usr/src/uts/common/io/tpm/tpm.c (revision b31b5de1357c915fe7dab4d9646d9d84f9fe69bc)
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 #include <tss/platform.h> 	/* from SUNWtss */
49 #include <tss/tpm.h> 		/* from SUNWtss */
50 
51 #include "tpm_tis.h"
52 #include "tpm_ddi.h"
53 #include "tpm_duration.h"
54 
55 #define	TPM_HEADER_SIZE 10
56 typedef enum {
57 	TPM_TAG_OFFSET = 0,
58 	TPM_PARAMSIZE_OFFSET = 2,
59 	TPM_RETURN_OFFSET = 6,
60 	TPM_COMMAND_CODE_OFFSET = 6,
61 } TPM_HEADER_OFFSET_T;
62 
63 /*
64  * This is to address some TPMs that does not report the correct duration
65  * and timeouts.  In our experience with the production TPMs, we encountered
66  * time errors such as GetCapability command from TPM reporting the timeout
67  * and durations in milliseconds rather than microseconds.  Some other TPMs
68  * report the value 0's
69  *
70  * Short Duration is based on section 11.3.4 of TIS speciciation, that
71  * TPM_GetCapability (short duration) commands should not be longer than 750ms
72  * and that section 11.3.7 states that TPM_ContinueSelfTest (medium duration)
73  * should not be longer than 1 second.
74  */
75 #define	DEFAULT_SHORT_DURATION	750000
76 #define	DEFAULT_MEDIUM_DURATION	1000000
77 #define	DEFAULT_LONG_DURATION	300000000
78 #define	DEFAULT_TIMEOUT_A	750000
79 #define	DEFAULT_TIMEOUT_B	2000000
80 #define	DEFAULT_TIMEOUT_C	750000
81 #define	DEFAULT_TIMEOUT_D	750000
82 
83 /*
84  * In order to test the 'millisecond bug', we test if DURATIONS and TIMEOUTS
85  * are unreasonably low...such as 10 milliseconds (TPM isn't that fast).
86  * and 400 milliseconds for long duration
87  */
88 #define	TEN_MILLISECONDS	10000	/* 10 milliseconds */
89 #define	FOUR_HUNDRED_MILLISECONDS 400000	/* 4 hundred milliseconds */
90 
91 /*
92  * TPM input/output buffer offsets
93  */
94 
95 typedef enum {
96 	TPM_CAP_RESPSIZE_OFFSET = 10,
97 	TPM_CAP_RESP_OFFSET = 14,
98 } TPM_CAP_RET_OFFSET_T;
99 
100 typedef enum {
101 	TPM_CAP_TIMEOUT_A_OFFSET = 14,
102 	TPM_CAP_TIMEOUT_B_OFFSET = 18,
103 	TPM_CAP_TIMEOUT_C_OFFSET = 22,
104 	TPM_CAP_TIMEOUT_D_OFFSET = 26,
105 } TPM_CAP_TIMEOUT_OFFSET_T;
106 
107 typedef enum {
108 	TPM_CAP_DUR_SHORT_OFFSET = 14,
109 	TPM_CAP_DUR_MEDIUM_OFFSET = 18,
110 	TPM_CAP_DUR_LONG_OFFSET = 22,
111 } TPM_CAP_DURATION_OFFSET_T;
112 
113 #define	TPM_CAP_VERSION_INFO_OFFSET	14
114 #define	TPM_CAP_VERSION_INFO_SIZE	15
115 
116 /*
117  * Internal TPM command functions
118  */
119 static int itpm_command(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz);
120 static int tpm_get_timeouts(tpm_state_t *tpm);
121 static int tpm_get_duration(tpm_state_t *tpm);
122 static int tpm_get_version(tpm_state_t *tpm);
123 static int tpm_continue_selftest(tpm_state_t *tpm);
124 
125 /*
126  * Internal TIS related functions
127  */
128 static int tpm_wait_for_stat(tpm_state_t *, uint8_t, clock_t);
129 static clock_t tpm_get_ordinal_duration(tpm_state_t *, uint8_t);
130 static int tis_check_active_locality(tpm_state_t *, char);
131 static int tis_request_locality(tpm_state_t *, char);
132 static void tis_release_locality(tpm_state_t *, char, int);
133 static int tis_init(tpm_state_t *);
134 static uint8_t tis_get_status(tpm_state_t *);
135 static int tis_send_data(tpm_state_t *, uint8_t *, size_t);
136 static int tis_recv_data(tpm_state_t *, uint8_t *, size_t);
137 
138 /* Auxilliary */
139 static int receive_data(tpm_state_t *, uint8_t *, size_t);
140 static inline int tpm_lock(tpm_state_t *);
141 static inline void tpm_unlock(tpm_state_t *);
142 static void tpm_cleanup(dev_info_t *, tpm_state_t *);
143 
144 /*
145  * Sun DDI/DDK entry points
146  */
147 
148 /* Declaration of autoconfig functions */
149 static int tpm_attach(dev_info_t *, ddi_attach_cmd_t);
150 static int tpm_detach(dev_info_t *, ddi_detach_cmd_t);
151 static int tpm_getinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
152 static int tpm_quiesce(dev_info_t *);
153 /* End of autoconfig functions */
154 
155 /* Declaration of driver entry point functions */
156 static int tpm_open(dev_t *, int, int, cred_t *);
157 static int tpm_close(dev_t, int, int, cred_t *);
158 static int tpm_read(dev_t, struct uio *, cred_t *);
159 static int tpm_write(dev_t, struct uio *, cred_t *);
160 /* End of driver entry point functions */
161 
162 /* cb_ops structure */
163 static struct cb_ops tpm_cb_ops = {
164 	tpm_open,
165 	tpm_close,
166 	nodev,		/* no strategy - nodev returns ENXIO */
167 	nodev,		/* no print */
168 	nodev,		/* no dump */
169 	tpm_read,
170 	tpm_write,
171 	nodev,		/* no ioctl */
172 	nodev,		/* no devmap */
173 	nodev,		/* no mmap */
174 	nodev,		/* no segmap */
175 	nochpoll,	/* returns ENXIO for non-pollable devices */
176 	ddi_prop_op,
177 	NULL,		/* streamtab struc */
178 	D_MP,		/* compatibility flags */
179 	CB_REV,		/* cb_ops revision number */
180 	nodev,		/* no aread */
181 	nodev		/* no awrite */
182 };
183 
184 /* dev_ops structure */
185 static struct dev_ops tpm_dev_ops = {
186 	DEVO_REV,
187 	0,		/* reference count */
188 	tpm_getinfo,
189 	nulldev,	/* no identify - nulldev returns 0 */
190 	nulldev,
191 	tpm_attach,
192 	tpm_detach,
193 	nodev,		/* no reset - nodev returns ENXIO */
194 	&tpm_cb_ops,
195 	(struct bus_ops *)NULL,
196 	nodev,		/* no power */
197 	tpm_quiesce
198 };
199 
200 /* modldrv structure */
201 static struct modldrv modldrv = {
202 	&mod_driverops,		/* Type: This is a driver */
203 	"TPM 1.2 driver",	/* Name of the module. */
204 	&tpm_dev_ops
205 };
206 
207 /* modlinkage structure */
208 static struct modlinkage tpm_ml = {
209 	MODREV_1,
210 	&modldrv,
211 	NULL
212 };
213 
214 static void *statep = NULL;
215 
216 /*
217  * TPM commands to get the TPM's properties, e.g.,timeout
218  */
219 /*ARGSUSED*/
220 static int
221 tpm_quiesce(dev_info_t *dip)
222 {
223 	return (DDI_SUCCESS);
224 }
225 
226 static uint32_t
227 load32(uchar_t *ptr, uint32_t offset)
228 {
229 	uint32_t val;
230 	bcopy(ptr + offset, &val, sizeof (uint32_t));
231 
232 	return (ntohl(val));
233 }
234 
235 /*
236  * Get the actual timeouts supported by the TPM by issuing TPM_GetCapability
237  * with the subcommand TPM_CAP_PROP_TIS_TIMEOUT
238  * TPM_GetCapability (TPM Main Part 3 Rev. 94, pg.38)
239  */
240 static int
241 tpm_get_timeouts(tpm_state_t *tpm)
242 {
243 	int ret;
244 	uint32_t timeout;   /* in milliseconds */
245 	uint32_t len;
246 
247 	/* The buffer size (30) needs room for 4 timeout values (uint32_t) */
248 	uint8_t buf[30] = {
249 		0, 193,		/* TPM_TAG_RQU_COMMAND */
250 		0, 0, 0, 22,	/* paramsize in bytes */
251 		0, 0, 0, 101,	/* TPM_ORD_GetCapability */
252 		0, 0, 0, 5,	/* TPM_CAP_Prop */
253 		0, 0, 0, 4,	/* SUB_CAP size in bytes */
254 		0, 0, 1, 21	/* TPM_CAP_PROP_TIS_TIMEOUT(0x115) */
255 	};
256 	char *myname = "tpm_get_timeout";
257 
258 	ASSERT(tpm != NULL);
259 
260 	ret = itpm_command(tpm, buf, sizeof (buf));
261 	if (ret != DDI_SUCCESS) {
262 		cmn_err(CE_WARN, "%s: itpm_command failed", myname);
263 		return (DDI_FAILURE);
264 	}
265 
266 	/*
267 	 * Get the length of the returned buffer
268 	 * Make sure that there are 4 timeout values returned
269 	 * length of the capability response is stored in data[10-13]
270 	 * Also the TPM is in network byte order
271 	 */
272 	len = load32(buf, TPM_CAP_RESPSIZE_OFFSET);
273 	if (len != 4 * sizeof (uint32_t)) {
274 		cmn_err(CE_WARN, "%s: capability response size should be %d"
275 		    "instead it's %d",
276 		    myname, (int)(4 * sizeof (uint32_t)), (int)len);
277 		return (DDI_FAILURE);
278 	}
279 
280 	/* Get the four timeout's: a,b,c,d (they are 4 bytes long each) */
281 	timeout = load32(buf, TPM_CAP_TIMEOUT_A_OFFSET);
282 	if (timeout == 0) {
283 		timeout = DEFAULT_TIMEOUT_A;
284 	} else if (timeout < TEN_MILLISECONDS) {
285 		/* timeout is in millisecond range (should be microseconds) */
286 		timeout *= 1000;
287 	}
288 	tpm->timeout_a = drv_usectohz(timeout);
289 
290 	timeout = load32(buf, TPM_CAP_TIMEOUT_B_OFFSET);
291 	if (timeout == 0) {
292 		timeout = DEFAULT_TIMEOUT_B;
293 	} else if (timeout < TEN_MILLISECONDS) {
294 		/* timeout is in millisecond range (should be microseconds) */
295 		timeout *= 1000;
296 	}
297 	tpm->timeout_b = drv_usectohz(timeout);
298 
299 	timeout = load32(buf, TPM_CAP_TIMEOUT_C_OFFSET);
300 	if (timeout == 0) {
301 		timeout = DEFAULT_TIMEOUT_C;
302 	} else if (timeout < TEN_MILLISECONDS) {
303 		/* timeout is in millisecond range (should be microseconds) */
304 		timeout *= 1000;
305 	}
306 	tpm->timeout_c = drv_usectohz(timeout);
307 
308 	timeout = load32(buf, TPM_CAP_TIMEOUT_D_OFFSET);
309 	if (timeout == 0) {
310 		timeout = DEFAULT_TIMEOUT_D;
311 	} else if (timeout < TEN_MILLISECONDS) {
312 		/* timeout is in millisecond range (should be microseconds) */
313 		timeout *= 1000;
314 	}
315 	tpm->timeout_d = drv_usectohz(timeout);
316 
317 	return (DDI_SUCCESS);
318 }
319 
320 /*
321  * Get the actual timeouts supported by the TPM by issuing TPM_GetCapability
322  * with the subcommand TPM_CAP_PROP_TIS_DURATION
323  * TPM_GetCapability (TPM Main Part 3 Rev. 94, pg.38)
324  */
325 static int
326 tpm_get_duration(tpm_state_t *tpm) {
327 	int ret;
328 	uint32_t duration;
329 	uint32_t len;
330 	uint8_t buf[30] = {
331 		0, 193,		/* TPM_TAG_RQU_COMMAND */
332 		0, 0, 0, 22,	/* paramsize in bytes */
333 		0, 0, 0, 101,	/* TPM_ORD_GetCapability */
334 		0, 0, 0, 5,	/* TPM_CAP_Prop */
335 		0, 0, 0, 4,	/* SUB_CAP size in bytes */
336 		0, 0, 1, 32	/* TPM_CAP_PROP_TIS_DURATION(0x120) */
337 	};
338 	char *myname = "tpm_get_duration";
339 
340 	ASSERT(tpm != NULL);
341 
342 	ret = itpm_command(tpm, buf, sizeof (buf));
343 	if (ret != DDI_SUCCESS) {
344 		cmn_err(CE_WARN, "%s: itpm_command failed with ret code: 0x%x",
345 			myname, ret);
346 		return (DDI_FAILURE);
347 	}
348 
349 	/*
350 	 * Get the length of the returned buffer
351 	 * Make sure that there are 3 duration values (S,M,L: in that order)
352 	 * length of the capability response is stored in data[10-13]
353 	 * Also the TPM is in network byte order
354 	 */
355 	len = load32(buf, TPM_CAP_RESPSIZE_OFFSET);
356 	if (len != 3 * sizeof (uint32_t)) {
357 		cmn_err(CE_WARN, "%s: capability response should be %d, "
358 		    "instead, it's %d",
359 		    myname, (int)(3 * sizeof (uint32_t)), (int)len);
360 		return (DDI_FAILURE);
361 	}
362 
363 	duration = load32(buf, TPM_CAP_DUR_SHORT_OFFSET);
364 	if (duration == 0) {
365 		duration = DEFAULT_SHORT_DURATION;
366 	} else if (duration < TEN_MILLISECONDS) {
367 		duration *= 1000;
368 	}
369 	tpm->duration[TPM_SHORT] = drv_usectohz(duration);
370 
371 	duration = load32(buf, TPM_CAP_DUR_MEDIUM_OFFSET);
372 	if (duration == 0) {
373 		duration = DEFAULT_MEDIUM_DURATION;
374 	} else if (duration < TEN_MILLISECONDS) {
375 		duration *= 1000;
376 	}
377 	tpm->duration[TPM_MEDIUM] = drv_usectohz(duration);
378 
379 	duration = load32(buf, TPM_CAP_DUR_LONG_OFFSET);
380 	if (duration == 0) {
381 		duration = DEFAULT_LONG_DURATION;
382 	} else if (duration < FOUR_HUNDRED_MILLISECONDS) {
383 		duration *= 1000;
384 	}
385 	tpm->duration[TPM_LONG] = drv_usectohz(duration);
386 
387 	/* Just make the undefined duration be the same as the LONG */
388 	tpm->duration[TPM_UNDEFINED] = tpm->duration[TPM_LONG];
389 
390 	return (DDI_SUCCESS);
391 }
392 
393 /*
394  * Get the actual timeouts supported by the TPM by issuing TPM_GetCapability
395  * with the subcommand TPM_CAP_PROP_TIS_DURATION
396  * TPM_GetCapability (TPM Main Part 3 Rev. 94, pg.38)
397  */
398 static int
399 tpm_get_version(tpm_state_t *tpm) {
400 	int ret;
401 	uint32_t len;
402 	char vendorId[5];
403 	/* If this buf is too small, the "vendor specific" data won't fit */
404 	uint8_t buf[64] = {
405 		0, 193,		/* TPM_TAG_RQU_COMMAND */
406 		0, 0, 0, 18,	/* paramsize in bytes */
407 		0, 0, 0, 101,	/* TPM_ORD_GetCapability */
408 		0, 0, 0, 0x1A,	/* TPM_CAP_VERSION_VAL */
409 		0, 0, 0, 0,	/* SUB_CAP size in bytes */
410 	};
411 	char *myname = "tpm_get_version";
412 
413 	ASSERT(tpm != NULL);
414 
415 	ret = itpm_command(tpm, buf, sizeof (buf));
416 	if (ret != DDI_SUCCESS) {
417 		cmn_err(CE_WARN, "%s: itpm_command failed with ret code: 0x%x",
418 			myname, ret);
419 		return (DDI_FAILURE);
420 	}
421 
422 	/*
423 	 * Get the length of the returned buffer.
424 	 */
425 	len = load32(buf, TPM_CAP_RESPSIZE_OFFSET);
426 	if (len < TPM_CAP_VERSION_INFO_SIZE) {
427 		cmn_err(CE_WARN, "%s: capability response should be greater"
428 		    " than %d, instead, it's %d",
429 		    myname,
430 		    TPM_CAP_VERSION_INFO_SIZE,
431 		    len);
432 		return (DDI_FAILURE);
433 	}
434 
435 	bcopy(buf + TPM_CAP_VERSION_INFO_OFFSET, &tpm->vers_info,
436 	    TPM_CAP_VERSION_INFO_SIZE);
437 
438 	bcopy(tpm->vers_info.tpmVendorID, vendorId,
439 	    sizeof (tpm->vers_info.tpmVendorID));
440 	vendorId[4] = '\0';
441 
442 	cmn_err(CE_NOTE, "!TPM found: Ver %d.%d, Rev %d.%d, "
443 	    "SpecLevel %d, errataRev %d, VendorId '%s'",
444 	    tpm->vers_info.version.major,	/* Version */
445 	    tpm->vers_info.version.minor,
446 	    tpm->vers_info.version.revMajor,	/* Revision */
447 	    tpm->vers_info.version.revMinor,
448 	    (int)ntohs(tpm->vers_info.specLevel),
449 	    tpm->vers_info.errataRev,
450 	    vendorId);
451 
452 	/*
453 	 * This driver only supports TPM Version 1.2
454 	 */
455 	if (tpm->vers_info.version.major != 1 &&
456 	    tpm->vers_info.version.minor != 2) {
457 		cmn_err(CE_WARN, "%s: Unsupported TPM version (%d.%d)",
458 		    myname,
459 		    tpm->vers_info.version.major,		/* Version */
460 		    tpm->vers_info.version.minor);
461 		return (DDI_FAILURE);
462 	}
463 
464 	return (DDI_SUCCESS);
465 }
466 
467 /*
468  * To prevent the TPM from complaining that certain functions are not tested
469  * we run this command when the driver attaches.
470  * For details see Section 4.2 of TPM Main Part 3 Command Specification
471  */
472 static int
473 tpm_continue_selftest(tpm_state_t *tpm) {
474 	int ret;
475 	uint8_t buf[10] = {
476 		0, 193,		/* TPM_TAG_RQU COMMAND */
477 		0, 0, 0, 10,	/* paramsize in bytes */
478 		0, 0, 0, 83	/* TPM_ORD_ContinueSelfTest */
479 	};
480 	char *myname = "tpm_continue_selftest";
481 
482 	/* Need a longer timeout */
483 	ret = itpm_command(tpm, buf, sizeof (buf));
484 	if (ret != DDI_SUCCESS) {
485 		cmn_err(CE_WARN, "%s: itpm_command failed", myname);
486 		return (DDI_FAILURE);
487 	}
488 
489 	return (DDI_SUCCESS);
490 }
491 /*
492  * Auxilary Functions
493  */
494 
495 /*
496  * Find out how long we should wait for the TPM command to complete a command
497  */
498 static clock_t
499 tpm_get_ordinal_duration(tpm_state_t *tpm, uint8_t ordinal)
500 {
501 	uint8_t index;
502 	char *myname = "tpm_get_ordinal_duration";
503 
504 	ASSERT(tpm != NULL);
505 
506 	/* Default and failure case for IFX */
507 	/* Is it a TSC_ORDINAL? */
508 	if (ordinal & TSC_ORDINAL_MASK) {
509 		if (ordinal > TSC_ORDINAL_MAX) {
510 			cmn_err(CE_WARN,
511 			    "%s: tsc ordinal: %d exceeds MAX: %d",
512 			    myname, ordinal, TSC_ORDINAL_MAX);
513 			return (0);
514 		}
515 		index = tsc_ords_duration[ordinal];
516 	} else {
517 		if (ordinal > TPM_ORDINAL_MAX) {
518 			cmn_err(CE_WARN,
519 			    "%s: ordinal %d exceeds MAX: %d",
520 			    myname, ordinal, TPM_ORDINAL_MAX);
521 			return (0);
522 		}
523 		index = tpm_ords_duration[ordinal];
524 	}
525 
526 	if (index > TPM_DURATION_MAX_IDX) {
527 		cmn_err(CE_WARN, "%s: FATAL:index '%d' is out of bound",
528 		    myname, index);
529 		return (0);
530 	}
531 	return (tpm->duration[index]);
532 }
533 
534 /*
535  * Internal TPM Transmit Function:
536  * Calls implementation specific sendto and receive
537  * The code assumes that the buffer is in network byte order
538  */
539 static int
540 itpm_command(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz)
541 {
542 	int ret;
543 	uint32_t count;
544 	char *myname = "itpm_command";
545 
546 	ASSERT(tpm != NULL && buf != NULL);
547 
548 	/* The byte order is network byte order so convert it */
549 	count = load32(buf, TPM_PARAMSIZE_OFFSET);
550 
551 	if (count == 0) {
552 		cmn_err(CE_WARN, "%s: count=0, no data? %d", myname,
553 		    (int)bufsiz);
554 		return (DDI_FAILURE);
555 	}
556 	if (count > bufsiz) {
557 		cmn_err(CE_WARN, "%s: invalid count value:count:%d > bufsiz %d",
558 		    myname, (int)count, (int)bufsiz);
559 		return (DDI_FAILURE);
560 	}
561 
562 	/* Send the command */
563 	ret = tis_send_data(tpm, buf, count);
564 	if (ret != DDI_SUCCESS) {
565 		cmn_err(CE_WARN, "%s: tis_send_data failed with error %x",
566 		    myname, ret);
567 		return (DDI_FAILURE);
568 	}
569 
570 	/*
571 	 * Now receive the data from the tpm
572 	 * Should at least receive "the common" 10 bytes (TPM_HEADER_SIZE)
573 	 */
574 	ret = tis_recv_data(tpm, buf, bufsiz);
575 	if (ret < TPM_HEADER_SIZE) {
576 		cmn_err(CE_WARN, "%s: tis_recv_data failed", myname);
577 		return (DDI_FAILURE);
578 	}
579 
580 	/* Check the return code */
581 	ret = load32(buf, TPM_RETURN_OFFSET);
582 	if (ret != TPM_SUCCESS) {
583 		cmn_err(CE_WARN, "%s: command failed with ret code: %x",
584 		    myname, ret);
585 		return (DDI_FAILURE);
586 	}
587 
588 	return (DDI_SUCCESS);
589 }
590 
591 /*
592  * Whenever the driver wants to write to the DATA_IO register, it must need
593  * to figure out the burstcount.  This is the amount of bytes it can write
594  * before having to wait for long LPC bus cycle
595  *
596  * Returns: 0 if error, burst count if sucess
597  */
598 static uint16_t
599 tpm_get_burstcount(tpm_state_t *tpm) {
600 	clock_t stop;
601 	uint16_t burstcnt;
602 
603 	ASSERT(tpm != NULL);
604 
605 	/*
606 	 * Spec says timeout should be TIMEOUT_D
607 	 * burst count is TPM_STS bits 8..23
608 	 */
609 	stop = ddi_get_lbolt() + tpm->timeout_d;
610 	do {
611 		/*
612 		 * burstcnt is stored as a little endian value
613 		 * 'ntohs' doesn't work since the value is not word-aligned
614 		 */
615 		burstcnt = ddi_get8(tpm->handle,
616 		    (uint8_t *)(tpm->addr+
617 		    TPM_STS_(tpm->locality)+1));
618 		burstcnt += ddi_get8(tpm->handle,
619 		    (uint8_t *)(tpm->addr+
620 		    TPM_STS_(tpm->locality)+2)) << 8;
621 
622 		if (burstcnt)
623 			return (burstcnt);
624 
625 		delay(tpm->timeout_poll);
626 	} while (ddi_get_lbolt() < stop);
627 
628 	return (0);
629 }
630 
631 /*
632  * Writing 1 to TPM_STS_CMD_READY bit in TPM_STS will do the following:
633  * 1. The TPM will clears IO buffers if any
634  * 2. The TPM will enters either Idle or Ready state within TIMEOUT_B
635  * (checked in the calling function)
636  */
637 static void
638 tpm_set_ready(tpm_state_t *tpm) {
639 	ASSERT(tpm != NULL);
640 
641 	ddi_put8(tpm->handle,
642 	    (uint8_t *)(tpm->addr+TPM_STS_(tpm->locality)),
643 	    TPM_STS_CMD_READY);
644 }
645 
646 static int
647 receive_data(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz) {
648 	int size = 0;
649 	int retried = 0;
650 	uint8_t stsbits;
651 
652 	/* A number of consecutive bytes that can be written to TPM */
653 	uint16_t burstcnt;
654 
655 	ASSERT(tpm != NULL && buf != NULL);
656 retry:
657 	while (size < bufsiz &&
658 		(tpm_wait_for_stat(tpm,
659 		    (TPM_STS_DATA_AVAIL|TPM_STS_VALID),
660 		    (ddi_get_lbolt() + tpm->timeout_c)) == DDI_SUCCESS)) {
661 		/*
662 		 * Burstcount should be available within TIMEOUT_D
663 		 * after STS is set to valid
664 		 * burstcount is dynamic, so have to get it each time
665 		 */
666 		burstcnt = tpm_get_burstcount(tpm);
667 		for (; burstcnt > 0 && size < bufsiz; burstcnt--) {
668 			buf[size++] = ddi_get8(tpm->handle,
669 			    (uint8_t *)(tpm->addr +
670 			    TPM_DATA_FIFO_(tpm->locality)));
671 		}
672 	}
673 	stsbits = tis_get_status(tpm);
674 	/* check to see if we need to retry (just once) */
675 	if (size < bufsiz && !(stsbits & TPM_STS_DATA_AVAIL) && retried == 0) {
676 		/* issue responseRetry (TIS 1.2 pg 54) */
677 		ddi_put8(tpm->handle,
678 		    (uint8_t *)(tpm->addr+TPM_STS_(tpm->locality)),
679 		    TPM_STS_RESPONSE_RETRY);
680 		/* update the retry counter so we only retry once */
681 		retried++;
682 		/* reset the size to 0 and reread the entire response */
683 		size = 0;
684 		goto retry;
685 	}
686 	return (size);
687 }
688 
689 /* Receive the data from the TPM */
690 static int
691 tis_recv_data(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz) {
692 	int ret;
693 	int size = 0;
694 	uint32_t expected, status;
695 	uint32_t cmdresult;
696 	char *myname = "tis_recv_data";
697 
698 	ASSERT(tpm != NULL && buf != NULL);
699 
700 	if (bufsiz < TPM_HEADER_SIZE) {
701 		/* There should be at least tag,paramsize,return code */
702 		cmn_err(CE_WARN, "%s: received data should contain at least "
703 		    "the header which is %d bytes long",
704 		    myname, TPM_HEADER_SIZE);
705 		goto OUT;
706 	}
707 
708 	/* Read tag(2 bytes), paramsize(4), and result(4) */
709 	size = receive_data(tpm, buf, TPM_HEADER_SIZE);
710 	if (size < TPM_HEADER_SIZE) {
711 		cmn_err(CE_WARN, "%s: getting the TPM_HEADER failed: size=%d",
712 		    myname, size);
713 		goto OUT;
714 	}
715 
716 	cmdresult = load32(buf, TPM_RETURN_OFFSET);
717 
718 	/* Get 'paramsize'(4 bytes)--it includes tag and paramsize */
719 	expected = load32(buf, TPM_PARAMSIZE_OFFSET);
720 	if (expected > bufsiz) {
721 		cmn_err(CE_WARN, "%s: paramSize is bigger "
722 		    "than the requested size: paramSize=%d bufsiz=%d result=%d",
723 		    myname, (int)expected, (int)bufsiz, cmdresult);
724 		goto OUT;
725 	}
726 
727 	/* Read in the rest of the data from the TPM */
728 	size += receive_data(tpm, (uint8_t *)&buf[TPM_HEADER_SIZE],
729 	    expected - TPM_HEADER_SIZE);
730 	if (size < expected) {
731 		cmn_err(CE_WARN, "%s: received data length=%d "
732 		    "is less than expected = %d", myname, size, expected);
733 		goto OUT;
734 	}
735 
736 	/* The TPM MUST set the state to stsValid within TIMEOUT_C */
737 	ret = tpm_wait_for_stat(tpm, TPM_STS_VALID,
738 	    ddi_get_lbolt() + tpm->timeout_c);
739 
740 	status = tis_get_status(tpm);
741 	if (ret != DDI_SUCCESS) {
742 		cmn_err(CE_WARN, "%s: TPM didn't set stsValid after its I/O: "
743 		    "status = 0x%08X", myname, status);
744 		goto OUT;
745 	}
746 
747 	/* There is still more data? */
748 	if (status & TPM_STS_DATA_AVAIL) {
749 		cmn_err(CE_WARN, "%s: Status TPM_STS_DATA_AVAIL set:0x%08X",
750 		    myname, status);
751 		goto OUT;
752 	}
753 
754 	/*
755 	 * Release the control of the TPM after we are done with it
756 	 * it...so others can also get a chance to send data
757 	 */
758 	tis_release_locality(tpm, tpm->locality, 0);
759 
760 OUT:
761 	tpm_set_ready(tpm);
762 	tis_release_locality(tpm, tpm->locality, 0);
763 	return (size);
764 }
765 
766 /*
767  * Send the data (TPM commands) to the Data IO register
768  */
769 static int
770 tis_send_data(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz) {
771 	int ret;
772 	uint8_t status;
773 	uint16_t burstcnt;
774 	uint32_t ordinal;
775 	size_t count = 0;
776 	char *myname = "tis_send_data";
777 
778 	ASSERT(tpm != NULL && buf != NULL);
779 
780 	if (bufsiz == 0) {
781 		cmn_err(CE_WARN, "%s: passed in argument bufsize is zero",
782 		    myname);
783 		return (DDI_FAILURE);
784 	}
785 
786 	/* Be in the right locality (aren't we always in locality 0?) */
787 	if (tis_request_locality(tpm, 0) != DDI_SUCCESS) {
788 		cmn_err(CE_WARN, "%s: tis_request_locality didn't enter "
789 		    "locality 0", myname);
790 		return (DDI_FAILURE);
791 	}
792 
793 	/* Put the TPM in ready state */
794 	status = tis_get_status(tpm);
795 
796 	if (!(status & TPM_STS_CMD_READY)) {
797 		tpm_set_ready(tpm);
798 		ret = tpm_wait_for_stat(tpm,
799 		    TPM_STS_CMD_READY,
800 		    (ddi_get_lbolt() + tpm->timeout_b));
801 		if (ret != DDI_SUCCESS) {
802 			cmn_err(CE_WARN, "%s: could not put the TPM "
803 			    "in the command ready state:"
804 			    "tpm_wait_for_stat returned error",
805 			    myname);
806 			goto FAIL;
807 		}
808 	}
809 
810 	/*
811 	 * Now we are ready to send command
812 	 * TPM's burstcount dictates how many bytes we can write at a time
813 	 * Burstcount is dynamic if INTF_CAPABILITY for static burstcount is
814 	 * not set.
815 	 */
816 	while (count < bufsiz - 1) {
817 		burstcnt = tpm_get_burstcount(tpm);
818 		if (burstcnt == 0) {
819 			cmn_err(CE_WARN, "%s: tpm_get_burstcnt returned error",
820 			    myname);
821 			ret = DDI_FAILURE;
822 			goto FAIL;
823 		}
824 
825 		for (; burstcnt > 0 && count < bufsiz - 1; burstcnt--) {
826 			ddi_put8(tpm->handle, (uint8_t *)(tpm->addr+
827 			    TPM_DATA_FIFO_(tpm->locality)), buf[count]);
828 			count++;
829 		}
830 		/* Wait for TPM to indicate that it is ready for more data */
831 		ret = tpm_wait_for_stat(tpm,
832 		    (TPM_STS_VALID | TPM_STS_DATA_EXPECT),
833 		    (ddi_get_lbolt() + tpm->timeout_c));
834 		if (ret != DDI_SUCCESS) {
835 			cmn_err(CE_WARN, "%s: TPM didn't enter stsvalid "
836 			    "state after sending the data:", myname);
837 			goto FAIL;
838 		}
839 	}
840 	/* We can't exit the loop above unless we wrote bufsiz-1 bytes */
841 
842 	/* Write last byte */
843 	ddi_put8(tpm->handle, (uint8_t *)(tpm->addr +
844 	    TPM_DATA_FIFO_(tpm->locality)), buf[count]);
845 	count++;
846 
847 	/* Wait for the TPM to enter Valid State */
848 	ret = tpm_wait_for_stat(tpm,
849 	    TPM_STS_VALID, (ddi_get_lbolt() + tpm->timeout_c));
850 	if (ret == DDI_FAILURE) {
851 		cmn_err(CE_WARN, "%s: tpm didn't enter Valid state", myname);
852 		goto FAIL;
853 	}
854 
855 	status = tis_get_status(tpm);
856 	/* The TPM should NOT be expecing more data at this point */
857 	if ((status & TPM_STS_DATA_EXPECT) != 0) {
858 		cmn_err(CE_WARN, "%s: DATA_EXPECT is set (shouldn't be) after "
859 		    "writing the last byte: status=0x%08X", myname, status);
860 		ret = DDI_FAILURE;
861 		goto FAIL;
862 	}
863 
864 	/*
865 	 * Final step: Writing TPM_STS_GO to TPM_STS
866 	 * register will actually send the command.
867 	 */
868 	ddi_put8(tpm->handle, (uint8_t *)(tpm->addr+TPM_STS_(tpm->locality)),
869 	    TPM_STS_GO);
870 
871 	/* Ordinal/Command_code is located in buf[6..9] */
872 	ordinal = load32(buf, TPM_COMMAND_CODE_OFFSET);
873 
874 	ret = tpm_wait_for_stat(tpm, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
875 	    ddi_get_lbolt() + tpm_get_ordinal_duration(tpm, ordinal));
876 	if (ret == DDI_FAILURE) {
877 		status = tis_get_status(tpm);
878 		if (!(status & TPM_STS_DATA_AVAIL) ||
879 		    !(status & TPM_STS_VALID)) {
880 			cmn_err(CE_WARN, "%s: TPM not ready or valid "
881 			    "(ordinal = %d timeout = %ld)",
882 			    myname, ordinal,
883 			    tpm_get_ordinal_duration(tpm, ordinal));
884 		} else {
885 			cmn_err(CE_WARN, "%s: tpm_wait_for_stat "
886 			    "(DATA_AVAIL | VALID) failed: STS = 0x%0X",
887 			    myname, status);
888 		}
889 		goto FAIL;
890 	}
891 	return (DDI_SUCCESS);
892 
893 FAIL:
894 	tpm_set_ready(tpm);
895 	tis_release_locality(tpm, tpm->locality, 0);
896 	return (ret);
897 }
898 
899 /*
900  * Clear XrequestUse and Xactivelocality, where X is the current locality
901  */
902 static void
903 tis_release_locality(tpm_state_t *tpm, char locality, int force) {
904 	ASSERT(tpm != NULL && locality >= 0 && locality < 5);
905 
906 	if (force ||
907 	    (ddi_get8(tpm->handle,
908 		(uchar_t *)(tpm->addr+TPM_ACCESS_(locality)))
909 	    & (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID))
910 	    == (TPM_ACCESS_REQUEST_PENDING | TPM_ACCESS_VALID)) {
911 		/*
912 		 * Writing 1 to active locality bit in TPM_ACCESS
913 		 * register reliquishes the control of the locality
914 		 */
915 		ddi_put8(tpm->handle,
916 		    (uint8_t *)(tpm->addr+TPM_ACCESS_(locality)),
917 		    TPM_ACCESS_ACTIVE_LOCALITY);
918 	}
919 }
920 
921 /*
922  * Checks whether the given locality is active
923  * Use TPM_ACCESS register and the masks TPM_ACCESS_VALID,TPM_ACTIVE_LOCALITY
924  */
925 static int
926 tis_check_active_locality(tpm_state_t *tpm, char locality) {
927 	uint8_t access_bits;
928 
929 	ASSERT(tpm != NULL && locality >= 0 && locality < 5);
930 
931 	access_bits = ddi_get8(tpm->handle,
932 	    (uint8_t *)(tpm->addr+TPM_ACCESS_(locality)));
933 	access_bits &= (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID);
934 
935 	if (access_bits == (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
936 		return (DDI_SUCCESS);
937 	else
938 		return (DDI_FAILURE);
939 }
940 
941 /* Request the TPM to be in the given locality */
942 static int
943 tis_request_locality(tpm_state_t *tpm, char locality) {
944 	clock_t timeout;
945 	int ret;
946 	char *myname = "tis_request_locality";
947 
948 	ASSERT(tpm != NULL && locality >= 0 && locality < 5);
949 
950 	ret = tis_check_active_locality(tpm, locality);
951 
952 	if (ret == DDI_SUCCESS) {
953 		/* Locality is already active */
954 		tpm->locality = locality;
955 		return (DDI_SUCCESS);
956 	}
957 
958 	ddi_put8(tpm->handle, tpm->addr+TPM_ACCESS_(locality),
959 	    TPM_ACCESS_REQUEST_USE);
960 	timeout = ddi_get_lbolt() + tpm->timeout_a;
961 
962 	/* Using polling */
963 	while (tis_check_active_locality(tpm, locality)
964 		!= DDI_SUCCESS) {
965 		if (ddi_get_lbolt() >= timeout) {
966 			cmn_err(CE_WARN, "%s (interrupt-disabled) "
967 			    "tis_request_locality timed out",
968 			    myname);
969 			return (DDI_FAILURE);
970 		}
971 		delay(tpm->timeout_poll);
972 	}
973 
974 	tpm->locality = locality;
975 	return (DDI_SUCCESS);
976 }
977 
978 /* Read the status register */
979 static uint8_t
980 tis_get_status(tpm_state_t *tpm) {
981 	return (ddi_get8(tpm->handle,
982 	    (uint8_t *)(tpm->addr+TPM_STS_(tpm->locality))));
983 }
984 
985 static int
986 tpm_wait_for_stat(tpm_state_t *tpm, uint8_t mask, clock_t absolute_timeout) {
987 	char *myname = "tpm_wait_for_stat";
988 
989 	/* Using polling */
990 	while ((tis_get_status(tpm) & mask) != mask) {
991 		if (ddi_get_lbolt() >= absolute_timeout) {
992 			/* Timeout reached */
993 			cmn_err(CE_WARN, "%s: using "
994 			    "polling:reached timeout",
995 			    myname);
996 			return (DDI_FAILURE);
997 		}
998 		delay(tpm->timeout_poll);
999 	}
1000 	return (DDI_SUCCESS);
1001 }
1002 
1003 /*
1004  * Initialize TPM device
1005  * 1. Find out supported interrupt capabilities
1006  * 2. Set up interrupt handler if supported (some BIOSes don't support
1007  * interrupts for TPMS, in which case we set up polling)
1008  * 3. Determine timeouts and commands duration
1009  */
1010 static int
1011 tis_init(tpm_state_t *tpm) {
1012 	uint32_t intf_caps;
1013 	int ret;
1014 	char *myname = "tis_init";
1015 	uintptr_t aptr = (uintptr_t)tpm->addr;
1016 
1017 	/*
1018 	 * Temporarily set up timeouts before we get the real timeouts
1019 	 * by issuing TPM_CAP commands (but to issue TPM_CAP commands,
1020 	 * you need TIMEOUTs defined...chicken and egg problem here.
1021 	 * TPM timeouts: Convert the milliseconds to clock cycles
1022 	 */
1023 	tpm->timeout_a = drv_usectohz(TIS_TIMEOUT_A);
1024 	tpm->timeout_b = drv_usectohz(TIS_TIMEOUT_B);
1025 	tpm->timeout_c = drv_usectohz(TIS_TIMEOUT_C);
1026 	tpm->timeout_d = drv_usectohz(TIS_TIMEOUT_D);
1027 	/*
1028 	 * Do the same with the duration (real duration will be filled out
1029 	 * when we call TPM_GetCapability to get the duration values from
1030 	 * the TPM itself).
1031 	 */
1032 	tpm->duration[TPM_SHORT] = drv_usectohz(TPM_DEFAULT_DURATION);
1033 	tpm->duration[TPM_MEDIUM] = drv_usectohz(TPM_DEFAULT_DURATION);
1034 	tpm->duration[TPM_LONG] = drv_usectohz(TPM_DEFAULT_DURATION);
1035 	tpm->duration[TPM_UNDEFINED] = drv_usectohz(TPM_DEFAULT_DURATION);
1036 
1037 	/* Find out supported capabilities */
1038 	intf_caps = ddi_get32(tpm->handle,
1039 	    (uint32_t *)(aptr + TPM_INTF_CAP_(0)));
1040 
1041 	/* Upper 3 bytes should always return 0 */
1042 	if (intf_caps & 0x7FFFFF00) {
1043 #ifdef DEBUG
1044 		cmn_err(CE_WARN, "%s: bad intf_caps value 0x%0X",
1045 		    myname, intf_caps);
1046 #endif
1047 		return (DDI_FAILURE);
1048 	}
1049 
1050 	/* These two interrupts are mandatory */
1051 	if (!(intf_caps & TPM_INTF_INT_LOCALITY_CHANGE_INT)) {
1052 		cmn_err(CE_WARN, "%s: Mandatory capability Locality Change Int "
1053 		    "not supported", myname);
1054 		return (DDI_FAILURE);
1055 	}
1056 	if (!(intf_caps & TPM_INTF_INT_DATA_AVAIL_INT)) {
1057 		cmn_err(CE_WARN, "%s: Mandatory capability Data Available Int "
1058 		    "not supported", myname);
1059 		return (DDI_FAILURE);
1060 	}
1061 
1062 	/*
1063 	 * Before we start writing anything to TPM's registers,
1064 	 * make sure we are in locality 0
1065 	 */
1066 	ret = tis_request_locality(tpm, 0);
1067 	if (ret != DDI_SUCCESS) {
1068 		cmn_err(CE_WARN, "%s: Unable to request locality 0", myname);
1069 		return (DDI_FAILURE);
1070 	} /* Now we can refer to the locality as tpm->locality */
1071 
1072 	tpm->timeout_poll = drv_usectohz(TPM_POLLING_TIMEOUT);
1073 	tpm->intr_enabled = 0;
1074 
1075 	/* Get the real timeouts from the TPM */
1076 	ret = tpm_get_timeouts(tpm);
1077 	if (ret != DDI_SUCCESS) {
1078 		cmn_err(CE_WARN, "%s: tpm_get_timeouts error", myname);
1079 		return (DDI_FAILURE);
1080 	}
1081 
1082 	ret = tpm_get_duration(tpm);
1083 	if (ret != DDI_SUCCESS) {
1084 		cmn_err(CE_WARN, "%s: tpm_get_duration error", myname);
1085 		return (DDI_FAILURE);
1086 	}
1087 
1088 	/* This gets the TPM version information */
1089 	ret = tpm_get_version(tpm);
1090 	if (ret != DDI_SUCCESS) {
1091 		cmn_err(CE_WARN, "%s: tpm_get_version error", myname);
1092 		return (DDI_FAILURE);
1093 	}
1094 
1095 	/*
1096 	 * Unless the TPM completes the test of its commands,
1097 	 * it can return an error when the untested commands are called
1098 	 */
1099 	ret = tpm_continue_selftest(tpm);
1100 	if (ret != DDI_SUCCESS) {
1101 		cmn_err(CE_WARN, "%s: tpm_continue_selftest error", myname);
1102 		return (DDI_FAILURE);
1103 	}
1104 	return (DDI_SUCCESS);
1105 }
1106 
1107 /*
1108  * Module Entry points
1109  */
1110 int
1111 _init(void)
1112 {
1113 	int ret;
1114 
1115 	ret = ddi_soft_state_init(&statep, sizeof (tpm_state_t), 1);
1116 	if (ret)
1117 		return (ret);
1118 
1119 	ret = mod_install(&tpm_ml);
1120 	if (ret != 0) {
1121 		cmn_err(CE_WARN, "_init: mod_install returned non-zero");
1122 		ddi_soft_state_fini(&statep);
1123 		return (ret);
1124 	}
1125 
1126 	return (ret);
1127 }
1128 
1129 int
1130 _info(struct modinfo *modinfop)
1131 {
1132 	int ret;
1133 	ret = mod_info(&tpm_ml, modinfop);
1134 	if (ret == 0)
1135 		cmn_err(CE_WARN, "mod_info failed: %d", ret);
1136 
1137 	return (ret);
1138 }
1139 
1140 int
1141 _fini()
1142 {
1143 	int ret;
1144 	ret = mod_remove(&tpm_ml);
1145 	if (ret != 0) {
1146 		return (ret);
1147 	}
1148 	ddi_soft_state_fini(&statep);
1149 
1150 	return (ret);
1151 }
1152 /* End of driver configuration functions */
1153 
1154 static int
1155 tpm_resume(tpm_state_t *tpm)
1156 {
1157 	mutex_enter(&tpm->pm_mutex);
1158 	if (!tpm->suspended) {
1159 		mutex_exit(&tpm->pm_mutex);
1160 		return (DDI_FAILURE);
1161 	}
1162 	tpm->suspended = 0;
1163 	cv_broadcast(&tpm->suspend_cv);
1164 	mutex_exit(&tpm->pm_mutex);
1165 
1166 	return (DDI_SUCCESS);
1167 }
1168 
1169 /*
1170  * Sun DDI/DDK entry points
1171  */
1172 static int
1173 tpm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
1174 {
1175 	int ret, idx;
1176 	int instance;
1177 	int nregs;
1178 	char *myname = "tpm_attach";
1179 	tpm_state_t *tpm = NULL;
1180 
1181 	ASSERT(dip != NULL);
1182 
1183 	instance = ddi_get_instance(dip);
1184 
1185 	/* Nothing out of ordinary here */
1186 	switch (cmd) {
1187 	case DDI_ATTACH:
1188 		ret = ddi_soft_state_zalloc(statep, instance);
1189 		if (ret != DDI_SUCCESS) {
1190 			cmn_err(CE_WARN, "%s could not allocate tpm_state_t",
1191 			    myname);
1192 			goto FAIL;
1193 		}
1194 		tpm = ddi_get_soft_state(statep, instance);
1195 		tpm->dip = dip;
1196 		break;
1197 	case DDI_RESUME:
1198 		tpm = ddi_get_soft_state(statep, instance);
1199 		if (tpm == NULL) {
1200 			cmn_err(CE_WARN, "%s: tpm_state_t is NULL",
1201 			    myname);
1202 			goto FAIL;
1203 		}
1204 		return (tpm_resume(tpm));
1205 	default:
1206 		cmn_err(CE_WARN, "%s: cmd %d is not implemented", myname, cmd);
1207 		ret = DDI_FAILURE;
1208 		goto FAIL;
1209 	}
1210 
1211 	/* Zeroize the flag, which is used to keep track of what is allocated */
1212 	tpm->flags = 0;
1213 
1214 	tpm->accattr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
1215 	tpm->accattr.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
1216 	tpm->accattr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
1217 
1218 	idx = 0;
1219 	ret = ddi_dev_nregs(tpm->dip, &nregs);
1220 	if (ret != DDI_SUCCESS)
1221 		goto FAIL;
1222 
1223 #ifdef DEBUG
1224 	cmn_err(CE_NOTE, "num registers = %d", nregs);
1225 #endif
1226 	/*
1227 	 * TPM vendors put the TPM registers in different
1228 	 * slots in their register lists.  They are not always
1229 	 * the 1st set of registers, for instance.
1230 	 * Loop until we find the set that matches the expected
1231 	 * register size (0x5000).
1232 	 */
1233 	for (idx = 0; idx < nregs; idx++) {
1234 		off_t regsize;
1235 
1236 		if ((ret = ddi_dev_regsize(tpm->dip, idx, &regsize)) !=
1237 		    DDI_SUCCESS)
1238 			goto FAIL;
1239 #ifdef DEBUG
1240 		cmn_err(CE_NOTE, "register set #%d size = 0x%0lX", idx,
1241 		    regsize);
1242 #endif
1243 		/* The TIS spec says the TPM registers must be 0x5000 bytes */
1244 		if (regsize == 0x5000)
1245 			break;
1246 	}
1247 	if (idx == nregs)
1248 		return (DDI_FAILURE);
1249 
1250 	ret = ddi_regs_map_setup(tpm->dip, idx, (caddr_t *)&tpm->addr,
1251 	    (offset_t)0, (offset_t)0x5000,
1252 	    &tpm->accattr, &tpm->handle);
1253 
1254 	if (ret != DDI_SUCCESS) {
1255 		goto FAIL;
1256 	}
1257 	tpm->flags |= TPM_DIDREGSMAP;
1258 
1259 	/* Enable TPM device according to the TIS specification */
1260 	ret = tis_init(tpm);
1261 	if (ret != DDI_SUCCESS) {
1262 		cmn_err(CE_WARN, "%s: tis_init() failed ret: %d",
1263 		    myname, ret);
1264 
1265 		/* We need to clean up the ddi_regs_map_setup call */
1266 		ddi_regs_map_free(&tpm->handle);
1267 		tpm->handle = NULL;
1268 		tpm->flags &= ~TPM_DIDREGSMAP;
1269 		goto FAIL;
1270 	}
1271 
1272 	/* Initialize the inter-process lock */
1273 	mutex_init(&tpm->dev_lock, NULL, MUTEX_DRIVER, NULL);
1274 	mutex_init(&tpm->pm_mutex, NULL, MUTEX_DRIVER, NULL);
1275 	cv_init(&tpm->suspend_cv, NULL, CV_DRIVER, NULL);
1276 
1277 	/* Set the suspend/resume property */
1278 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
1279 	    "pm-hardware-state", "needs-suspend-resume");
1280 
1281 	mutex_enter(&tpm->pm_mutex);
1282 	tpm->suspended = 0;
1283 	mutex_exit(&tpm->pm_mutex);
1284 
1285 	tpm->flags |= TPM_DID_MUTEX;
1286 
1287 	/* Initialize the buffer and the lock associated with it */
1288 	tpm->bufsize = TPM_IO_BUF_SIZE;
1289 	tpm->iobuf = kmem_zalloc((sizeof (uint8_t))*(tpm->bufsize), KM_SLEEP);
1290 	if (tpm->iobuf == NULL) {
1291 		cmn_err(CE_WARN, "%s: failed to allocate iobuf", myname);
1292 		goto FAIL;
1293 	}
1294 	tpm->flags |= TPM_DID_IO_ALLOC;
1295 
1296 	mutex_init(&tpm->iobuf_lock, NULL, MUTEX_DRIVER, NULL);
1297 	tpm->flags |= TPM_DID_IO_MUTEX;
1298 
1299 	cv_init(&tpm->iobuf_cv, NULL, CV_DRIVER, NULL);
1300 	tpm->flags |= TPM_DID_IO_CV;
1301 
1302 	/* Create minor node */
1303 	ret = ddi_create_minor_node(dip, "tpm", S_IFCHR, ddi_get_instance(dip),
1304 	    DDI_PSEUDO, 0);
1305 	if (ret != DDI_SUCCESS) {
1306 		cmn_err(CE_WARN, "%s: ddi_create_minor_node failed", myname);
1307 		goto FAIL;
1308 	}
1309 	tpm->flags |= TPM_DIDMINOR;
1310 
1311 	return (DDI_SUCCESS);
1312 FAIL:
1313 	if (tpm != NULL) {
1314 		tpm_cleanup(dip, tpm);
1315 		ddi_soft_state_free(statep, instance);
1316 		tpm = NULL;
1317 	}
1318 
1319 	return (DDI_FAILURE);
1320 }
1321 
1322 /*
1323  * Called by tpm_detach and tpm_attach (only on failure)
1324  * Free up the resources that are allocated
1325  */
1326 static void
1327 tpm_cleanup(dev_info_t *dip, tpm_state_t *tpm)
1328 {
1329 	if (tpm == NULL)
1330 		return;
1331 
1332 	if (tpm->flags & TPM_DID_MUTEX) {
1333 		mutex_destroy(&tpm->dev_lock);
1334 		tpm->flags &= ~(TPM_DID_MUTEX);
1335 	}
1336 	if (tpm->flags & TPM_DID_IO_ALLOC) {
1337 		ASSERT(tpm->iobuf != NULL);
1338 		kmem_free(tpm->iobuf, (sizeof (uint8_t))*(tpm->bufsize));
1339 		tpm->flags &= ~(TPM_DID_IO_ALLOC);
1340 	}
1341 	if (tpm->flags & TPM_DID_IO_MUTEX) {
1342 		mutex_destroy(&tpm->iobuf_lock);
1343 		tpm->flags &= ~(TPM_DID_IO_MUTEX);
1344 	}
1345 	if (tpm->flags & TPM_DID_IO_CV) {
1346 		cv_destroy(&tpm->iobuf_cv);
1347 		tpm->flags &= ~(TPM_DID_IO_CV);
1348 	}
1349 	if (tpm->flags & TPM_DIDREGSMAP) {
1350 		/* Free the mapped addresses */
1351 		if (tpm->handle != NULL)
1352 			ddi_regs_map_free(&tpm->handle);
1353 		tpm->flags &= ~(TPM_DIDREGSMAP);
1354 	}
1355 	if (tpm->flags & TPM_DIDMINOR) {
1356 		/* Remove minor node */
1357 		ddi_remove_minor_node(dip, NULL);
1358 		tpm->flags &= ~(TPM_DIDMINOR);
1359 	}
1360 }
1361 
1362 static int
1363 tpm_suspend(tpm_state_t *tpm)
1364 {
1365 	if (tpm == NULL)
1366 		return (DDI_FAILURE);
1367 	mutex_enter(&tpm->pm_mutex);
1368 	if (tpm->suspended) {
1369 		mutex_exit(&tpm->pm_mutex);
1370 		return (DDI_SUCCESS);
1371 	}
1372 	tpm->suspended = 1;
1373 	mutex_exit(&tpm->pm_mutex);
1374 
1375 	return (DDI_SUCCESS);
1376 }
1377 
1378 static int
1379 tpm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1380 {
1381 	char *myname = "tpm_detach";
1382 	int instance;
1383 	tpm_state_t *tpm;
1384 
1385 	ASSERT(dip != NULL);
1386 
1387 	instance = ddi_get_instance(dip);
1388 	if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1389 		cmn_err(CE_WARN, "%s: stored pointer to tpm state is NULL",
1390 		    myname);
1391 		return (ENXIO);
1392 	}
1393 
1394 	switch (cmd) {
1395 	case DDI_DETACH:
1396 		/* Body is after the switch stmt */
1397 		break;
1398 	case DDI_SUSPEND:
1399 		return (tpm_suspend(tpm));
1400 	default:
1401 		cmn_err(CE_WARN, "%s: case %d not implemented", myname, cmd);
1402 		return (DDI_FAILURE);
1403 	}
1404 
1405 	/* Since we are freeing tpm structure, we need to gain the lock */
1406 
1407 	tpm_cleanup(dip, tpm);
1408 
1409 	mutex_destroy(&tpm->pm_mutex);
1410 	cv_destroy(&tpm->suspend_cv);
1411 
1412 	/* Free the soft state */
1413 	ddi_soft_state_free(statep, instance);
1414 	tpm = NULL;
1415 
1416 	return (DDI_SUCCESS);
1417 }
1418 
1419 /*ARGSUSED*/
1420 static int
1421 tpm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
1422 {
1423 	char *myname = "tpm_getinfo";
1424 	int instance;
1425 	tpm_state_t *tpm;
1426 
1427 	instance = ddi_get_instance(dip);
1428 	if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1429 		cmn_err(CE_WARN, "%s: stored pointer to tpm state is NULL",
1430 		    myname);
1431 		return (DDI_FAILURE);
1432 	}
1433 
1434 	switch (cmd) {
1435 	case DDI_INFO_DEVT2DEVINFO:
1436 		*resultp = tpm->dip;
1437 		break;
1438 	case DDI_INFO_DEVT2INSTANCE:
1439 		*resultp = 0;
1440 		break;
1441 	default:
1442 		cmn_err(CE_WARN, "%s: cmd %d is not implemented", myname, cmd);
1443 		return (DDI_FAILURE);
1444 	}
1445 	return (DDI_SUCCESS);
1446 }
1447 
1448 /*
1449  * Driver entry points
1450  */
1451 
1452 /*ARGSUSED*/
1453 static int
1454 tpm_open(dev_t *devp, int flag, int otyp, cred_t *cred)
1455 {
1456 	char *myname = "tpm_open";
1457 	int instance;
1458 	tpm_state_t *tpm;
1459 
1460 	ASSERT(devp != NULL);
1461 
1462 	instance = getminor(*devp);
1463 	if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1464 		cmn_err(CE_WARN, "%s: stored pointer to tpm state is NULL",
1465 		    myname);
1466 		return (ENXIO);
1467 	}
1468 	if (otyp != OTYP_CHR) {
1469 		cmn_err(CE_WARN, "%s: otyp(%d) != OTYP_CHR(%d)",
1470 		    myname, otyp, OTYP_CHR);
1471 		return (EINVAL);
1472 	}
1473 	mutex_enter(&tpm->pm_mutex);
1474 	while (tpm->suspended)
1475 		cv_wait(&tpm->suspend_cv, &tpm->pm_mutex);
1476 	mutex_exit(&tpm->pm_mutex);
1477 
1478 	mutex_enter(&tpm->dev_lock);
1479 	if (tpm->dev_held) {
1480 		cmn_err(CE_WARN, "%s: the device is already being used",
1481 		    myname);
1482 		mutex_exit(&tpm->dev_lock);
1483 		return (EBUSY);
1484 	}
1485 
1486 	/* The device is free so mark it busy */
1487 	tpm->dev_held = 1;
1488 	mutex_exit(&tpm->dev_lock);
1489 
1490 	return (0);
1491 }
1492 
1493 /*ARGSUSED*/
1494 static int
1495 tpm_close(dev_t dev, int flag, int otyp, cred_t *cred)
1496 {
1497 	char *myname = "tpm_close";
1498 	int instance;
1499 	tpm_state_t *tpm;
1500 
1501 	instance = getminor(dev);
1502 	if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1503 		cmn_err(CE_WARN, "%s: stored pointer to tpm state is NULL",
1504 		    myname);
1505 		return (ENXIO);
1506 	}
1507 	if (otyp != OTYP_CHR) {
1508 		cmn_err(CE_WARN, "%s: otyp(%d) != OTYP_CHR(%d)",
1509 		    myname, otyp, OTYP_CHR);
1510 		return (EINVAL);
1511 	}
1512 	mutex_enter(&tpm->pm_mutex);
1513 	while (tpm->suspended)
1514 		cv_wait(&tpm->suspend_cv, &tpm->pm_mutex);
1515 	mutex_exit(&tpm->pm_mutex);
1516 
1517 	ASSERT(tpm->dev_held);
1518 
1519 	mutex_enter(&tpm->dev_lock);
1520 	ASSERT(mutex_owned(&tpm->dev_lock));
1521 	tpm->dev_held = 0;
1522 	mutex_exit(&tpm->dev_lock);
1523 
1524 	return (0);
1525 }
1526 
1527 /*ARGSUSED*/
1528 static int
1529 tpm_read(dev_t dev, struct uio *uiop, cred_t *credp)
1530 {
1531 	int ret;
1532 	uint32_t size;
1533 	char *myname = "tpm_read";
1534 	int instance;
1535 	tpm_state_t *tpm;
1536 
1537 	instance = getminor(dev);
1538 	if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1539 		cmn_err(CE_WARN, "%s: stored pointer to tpm state is NULL",
1540 		    myname);
1541 		return (ENXIO);
1542 	}
1543 	if (uiop == NULL) {
1544 		cmn_err(CE_WARN, "%s: passed in uiop is NULL", myname);
1545 		return (EFAULT);
1546 	}
1547 
1548 	mutex_enter(&tpm->pm_mutex);
1549 	while (tpm->suspended)
1550 		cv_wait(&tpm->suspend_cv, &tpm->pm_mutex);
1551 	mutex_exit(&tpm->pm_mutex);
1552 
1553 	/* Receive the data after requiring the lock */
1554 	ret = tpm_lock(tpm);
1555 
1556 	/* Timeout reached */
1557 	if (ret == ETIME)
1558 		return (ret);
1559 
1560 	if (uiop->uio_resid > tpm->bufsize) {
1561 		cmn_err(CE_WARN, "%s: read_in data is bigger "
1562 		    "than tpm->bufsize:read in:%d, bufsiz:%d",
1563 		    myname, (int)uiop->uio_resid, (int)tpm->bufsize);
1564 		ret = EIO;
1565 		goto OUT;
1566 	}
1567 
1568 	ret = tis_recv_data(tpm, tpm->iobuf, tpm->bufsize);
1569 	if (ret < TPM_HEADER_SIZE) {
1570 		cmn_err(CE_WARN, "%s: tis_recv_data returned error", myname);
1571 		ret = EIO;
1572 		goto OUT;
1573 	}
1574 
1575 	size = load32(tpm->iobuf, 2);
1576 	if (ret != size) {
1577 		cmn_err(CE_WARN, "%s: tis_recv_data:"
1578 		    "expected size=%d, actually read=%d",
1579 		    myname, size, ret);
1580 		ret = EIO;
1581 		goto OUT;
1582 	}
1583 
1584 	/* Send the buffer from the kernel to the userspace */
1585 	ret = uiomove(tpm->iobuf, size, UIO_READ, uiop);
1586 	if (ret) {
1587 		cmn_err(CE_WARN, "%s: uiomove returned error", myname);
1588 		goto OUT;
1589 	}
1590 
1591 	/* Zeroize the buffer... */
1592 	bzero(tpm->iobuf, tpm->bufsize);
1593 	ret = DDI_SUCCESS;
1594 OUT:
1595 	/* We are done now: wake up the waiting threads */
1596 	tpm_unlock(tpm);
1597 
1598 	return (ret);
1599 }
1600 
1601 /*ARGSUSED*/
1602 static int
1603 tpm_write(dev_t dev, struct uio *uiop, cred_t *credp)
1604 {
1605 	int ret;
1606 	size_t len;
1607 	uint32_t size;
1608 	char *myname = "tpm_write";
1609 	int instance;
1610 	tpm_state_t *tpm;
1611 
1612 	instance = getminor(dev);
1613 	if ((tpm = ddi_get_soft_state(statep, instance)) == NULL) {
1614 		cmn_err(CE_WARN, "%s: stored pointer to tpm state is NULL",
1615 		    myname);
1616 		return (ENXIO);
1617 	}
1618 
1619 	if (uiop == NULL) {
1620 		cmn_err(CE_WARN, "%s: passed in uiop is NULL", myname);
1621 		return (EFAULT);
1622 	}
1623 
1624 	mutex_enter(&tpm->pm_mutex);
1625 	while (tpm->suspended)
1626 		cv_wait(&tpm->suspend_cv, &tpm->pm_mutex);
1627 	mutex_exit(&tpm->pm_mutex);
1628 
1629 	len = uiop->uio_resid;
1630 	if (len == 0) {
1631 		cmn_err(CE_WARN, "%s: requested read of len 0", myname);
1632 		return (0);
1633 	}
1634 
1635 	/* Get the lock for using iobuf */
1636 	ret = tpm_lock(tpm);
1637 	/* Timeout Reached */
1638 	if (ret == ETIME)
1639 		return (ret);
1640 
1641 	/* Copy the header and parse the structure to find out the size... */
1642 	ret = uiomove(tpm->iobuf, TPM_HEADER_SIZE, UIO_WRITE, uiop);
1643 	if (ret) {
1644 		cmn_err(CE_WARN, "%s: uiomove returned error"
1645 		    "while getting the the header",
1646 		    myname);
1647 		goto OUT;
1648 	}
1649 
1650 	/* Get the buffersize from the command buffer structure */
1651 	size = load32(tpm->iobuf, TPM_PARAMSIZE_OFFSET);
1652 
1653 	/* Copy the command to the contiguous buffer */
1654 	if (size > tpm->bufsize) {
1655 		cmn_err(CE_WARN, "%s: size %d is greater than "
1656 		    "the tpm's input buffer size %d",
1657 		    myname, (int)size, (int)tpm->bufsize);
1658 		ret = ENXIO;
1659 		goto OUT;
1660 	}
1661 
1662 	/* Copy the buffer from the userspace to kernel */
1663 	ret = uiomove(tpm->iobuf+TPM_HEADER_SIZE, size-TPM_HEADER_SIZE,
1664 	    UIO_WRITE, uiop);
1665 
1666 	if (ret) {
1667 		cmn_err(CE_WARN, "%s: uiomove returned error"
1668 		    "while getting the rest of the command", myname);
1669 		goto OUT;
1670 	}
1671 
1672 	/* Send the command */
1673 	ret = tis_send_data(tpm, tpm->iobuf, size);
1674 	if (ret != DDI_SUCCESS) {
1675 		cmn_err(CE_WARN, "%s: tis_send_data returned error", myname);
1676 		ret = EFAULT;
1677 		goto OUT;
1678 	}
1679 
1680 	/* Zeroize the buffer... */
1681 	bzero(tpm->iobuf, tpm->bufsize);
1682 	ret = DDI_SUCCESS;
1683 OUT:
1684 	tpm_unlock(tpm);
1685 	return (ret);
1686 }
1687 
1688 /*
1689  * This is to deal with the contentions for the iobuf
1690  */
1691 static inline int
1692 tpm_lock(tpm_state_t *tpm)
1693 {
1694 	int ret;
1695 	clock_t timeout;
1696 
1697 	mutex_enter(&tpm->iobuf_lock);
1698 	ASSERT(mutex_owned(&tpm->iobuf_lock));
1699 
1700 	timeout = ddi_get_lbolt() + drv_usectohz(TPM_IO_TIMEOUT);
1701 
1702 	/* Wait until the iobuf becomes free with the timeout */
1703 	while (tpm->iobuf_inuse) {
1704 		ret = cv_timedwait(&tpm->iobuf_cv, &tpm->iobuf_lock, timeout);
1705 		if (ret <= 0) {
1706 			/* Timeout reached */
1707 			mutex_exit(&tpm->iobuf_lock);
1708 			cmn_err(CE_WARN, "tpm_lock:iorequest timed out");
1709 			return (ETIME);
1710 		}
1711 	}
1712 	tpm->iobuf_inuse = 1;
1713 	mutex_exit(&tpm->iobuf_lock);
1714 	return (0);
1715 }
1716 
1717 /*
1718  * This is to deal with the contentions for the iobuf
1719  */
1720 static inline void
1721 tpm_unlock(tpm_state_t *tpm)
1722 {
1723 	/* Wake up the waiting threads */
1724 	mutex_enter(&tpm->iobuf_lock);
1725 	ASSERT(tpm->iobuf_inuse == 1 && mutex_owned(&tpm->iobuf_lock));
1726 	tpm->iobuf_inuse = 0;
1727 	cv_broadcast(&tpm->iobuf_cv);
1728 	mutex_exit(&tpm->iobuf_lock);
1729 }
1730