Home | History | Annotate | Download | only in tpm
      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