nuke pkcs11_tpm and tpmadm(1m)
[unleashed.git] / usr / src / uts / common / io / tpm / tpm.c
blobcce1ecb08aec0a32fd080091cbc80e203e065a93
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
28 * TPM 1.2 Driver for the TPMs that follow TIS v1.2
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 */
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 */
46 #include <sys/byteorder.h> /* for ntohs, ntohl, htons, htonl */
48 #ifdef sun4v
49 #include <sys/hypervisor_api.h>
50 #include <sys/hsvc.h>
51 #endif
53 #include <tss/platform.h> /* from SUNWtss */
54 #include <tss/tpm.h> /* from SUNWtss */
56 #include "tpm_tis.h"
57 #include "tpm_ddi.h"
58 #include "tpm_duration.h"
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;
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
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.
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
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
93 #define TEN_MILLISECONDS 10000 /* 10 milliseconds */
94 #define FOUR_HUNDRED_MILLISECONDS 400000 /* 4 hundred milliseconds */
96 #define DEFAULT_LOCALITY 0
98 * TPM input/output buffer offsets
101 typedef enum {
102 TPM_CAP_RESPSIZE_OFFSET = 10,
103 TPM_CAP_RESP_OFFSET = 14,
104 } TPM_CAP_RET_OFFSET_T;
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;
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;
119 #define TPM_CAP_VERSION_INFO_OFFSET 14
120 #define TPM_CAP_VERSION_INFO_SIZE 15
123 * Internal TPM command functions
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);
132 * Internal TIS related functions
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);
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 *);
151 * Sun DDI/DDK entry points
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 */
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 */
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 */
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
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
213 /* modlinkage structure */
214 static struct modlinkage tpm_ml = {
215 MODREV_1,
216 &modldrv,
217 NULL
221 #ifdef KCF_TPM_RNG_PROVIDER
223 #define IDENT_TPMRNG "TPM Random Number Generator"
225 #include <sys/crypto/common.h>
226 #include <sys/crypto/impl.h>
227 #include <sys/crypto/spi.h>
229 * CSPI information (entry points, provider info, etc.)
231 static void tpmrng_provider_status(crypto_provider_handle_t, uint_t *);
233 static crypto_control_ops_t tpmrng_control_ops = {
234 tpmrng_provider_status
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);
240 static int tpmrng_generate_random(crypto_provider_handle_t,
241 crypto_session_id_t, uchar_t *, size_t, crypto_req_handle_t);
243 static crypto_random_number_ops_t tpmrng_random_number_ops = {
244 tpmrng_seed_random,
245 tpmrng_generate_random
248 static int tpmrng_ext_info(crypto_provider_handle_t,
249 crypto_provider_ext_info_t *,
250 crypto_req_handle_t);
252 static crypto_provider_management_ops_t tpmrng_extinfo_op = {
253 tpmrng_ext_info,
254 NULL,
255 NULL,
256 NULL
259 static int tpmrng_register(tpm_state_t *);
260 static int tpmrng_unregister(tpm_state_t *);
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
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,
288 NULL,
290 NULL
292 #endif /* KCF_TPM_RNG_PROVIDER */
294 static void *statep = NULL;
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.
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); }
309 * TPM accessor functions
311 #ifdef sun4v
313 extern uint64_t
314 hcall_tpm_get(uint64_t, uint64_t, uint64_t, uint64_t *);
316 extern uint64_t
317 hcall_tpm_put(uint64_t, uint64_t, uint64_t, uint64_t);
319 static inline uint8_t
320 tpm_get8(tpm_state_t *tpm, unsigned long offset)
322 uint64_t value;
324 ASSERT(tpm != NULL);
325 (void) hcall_tpm_get(tpm->locality, offset, sizeof (uint8_t), &value);
326 return ((uint8_t)value);
329 static inline uint32_t
330 tpm_get32(tpm_state_t *tpm, unsigned long offset)
332 uint64_t value;
334 ASSERT(tpm != NULL);
335 (void) hcall_tpm_get(tpm->locality, offset, sizeof (uint32_t), &value);
336 return ((uint32_t)value);
339 static inline void
340 tpm_put8(tpm_state_t *tpm, unsigned long offset, uint8_t value)
342 ASSERT(tpm != NULL);
343 (void) hcall_tpm_put(tpm->locality, offset, sizeof (uint8_t), value);
346 #else
348 static inline uint8_t
349 tpm_get8(tpm_state_t *tpm, unsigned long offset)
351 ASSERT(tpm != NULL);
353 return (ddi_get8(tpm->handle,
354 (uint8_t *)(TPM_LOCALITY_OFFSET(tpm->locality) |
355 (uintptr_t)tpm->addr + offset)));
358 static inline uint32_t
359 tpm_get32(tpm_state_t *tpm, unsigned long offset)
361 ASSERT(tpm != NULL);
362 return (ddi_get32(tpm->handle,
363 (uint32_t *)(TPM_LOCALITY_OFFSET(tpm->locality) |
364 (uintptr_t)tpm->addr + offset)));
367 static inline void
368 tpm_put8(tpm_state_t *tpm, unsigned long offset, uint8_t value)
370 ASSERT(tpm != NULL);
371 ddi_put8(tpm->handle,
372 (uint8_t *)(TPM_LOCALITY_OFFSET(tpm->locality) |
373 (uintptr_t)tpm->addr + offset), value);
376 #endif /* sun4v */
379 * TPM commands to get the TPM's properties, e.g.,timeout
381 /*ARGSUSED*/
382 static int
383 tpm_quiesce(dev_info_t *dip)
385 return (DDI_SUCCESS);
388 static uint32_t
389 load32(uchar_t *ptr, uint32_t offset)
391 uint32_t val;
392 bcopy(ptr + offset, &val, sizeof (uint32_t));
394 return (ntohl(val));
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)
402 static int
403 tpm_get_timeouts(tpm_state_t *tpm)
405 int ret;
406 uint32_t timeout; /* in milliseconds */
407 uint32_t len;
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) */
418 char *myname = "tpm_get_timeout";
420 ASSERT(tpm != NULL);
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);
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
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);
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;
454 tpm->timeout_a = drv_usectohz(timeout);
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;
463 tpm->timeout_b = drv_usectohz(timeout);
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;
472 tpm->timeout_c = drv_usectohz(timeout);
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;
481 tpm->timeout_d = drv_usectohz(timeout);
483 return (DDI_SUCCESS);
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)
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) */
504 char *myname = "tpm_get_duration";
506 ASSERT(tpm != NULL);
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);
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
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);
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;
539 tpm->duration[TPM_SHORT] = drv_usectohz(duration);
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;
547 tpm->duration[TPM_MEDIUM] = drv_usectohz(duration);
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;
555 tpm->duration[TPM_LONG] = drv_usectohz(duration);
557 /* Just make the undefined duration be the same as the LONG */
558 tpm->duration[TPM_UNDEFINED] = tpm->duration[TPM_LONG];
560 return (DDI_SUCCESS);
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)
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 */
581 char *myname = "tpm_get_version";
583 ASSERT(tpm != NULL);
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);
595 * Get the length of the returned buffer.
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);
607 bcopy(buf + TPM_CAP_VERSION_INFO_OFFSET, &tpm->vers_info,
608 TPM_CAP_VERSION_INFO_SIZE);
610 bcopy(tpm->vers_info.tpmVendorID, vendorId,
611 sizeof (tpm->vers_info.tpmVendorID));
612 vendorId[4] = '\0';
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);
625 * This driver only supports TPM Version 1.2
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);
636 return (DDI_SUCCESS);
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
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 */
652 char *myname = "tpm_continue_selftest";
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);
663 return (DDI_SUCCESS);
666 * Auxilary Functions
670 * Find out how long we should wait for the TPM command to complete a command
672 static clock_t
673 tpm_get_ordinal_duration(tpm_state_t *tpm, uint8_t ordinal)
675 uint8_t index;
676 char *myname = "tpm_get_ordinal_duration";
678 ASSERT(tpm != NULL);
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);
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);
701 index = tpm_ords_duration[ordinal];
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);
711 return (tpm->duration[index]);
715 * Internal TPM Transmit Function:
716 * Calls implementation specific sendto and receive
717 * The code assumes that the buffer is in network byte order
719 static int
720 itpm_command(tpm_state_t *tpm, uint8_t *buf, size_t bufsiz)
722 int ret;
723 uint32_t count;
724 char *myname = "itpm_command";
726 ASSERT(tpm != NULL && buf != NULL);
728 /* The byte order is network byte order so convert it */
729 count = load32(buf, TPM_PARAMSIZE_OFFSET);
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);
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);
750 * Now receive the data from the tpm
751 * Should at least receive "the common" 10 bytes (TPM_HEADER_SIZE)
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);
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);
774 return (DDI_SUCCESS);
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
782 * Returns: 0 if error, burst count if sucess
784 static uint16_t
785 tpm_get_burstcount(tpm_state_t *tpm) {
786 clock_t stop;
787 uint16_t burstcnt;
789 ASSERT(tpm != NULL);
792 * Spec says timeout should be TIMEOUT_D
793 * burst count is TPM_STS bits 8..23
795 stop = ddi_get_lbolt() + tpm->timeout_d;
796 do {
798 * burstcnt is stored as a little endian value
799 * 'ntohs' doesn't work since the value is not word-aligned
801 burstcnt = tpm_get8(tpm, TPM_STS + 1);
802 burstcnt += tpm_get8(tpm, TPM_STS + 2) << 8;
804 if (burstcnt)
805 return (burstcnt);
807 delay(tpm->timeout_poll);
808 } while (ddi_get_lbolt() < stop);
810 return (0);
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)
819 static void
820 tpm_set_ready(tpm_state_t *tpm) {
821 tpm_put8(tpm, TPM_STS, TPM_STS_CMD_READY);
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;
830 /* A number of consecutive bytes that can be written to TPM */
831 uint16_t burstcnt;
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)) {
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
844 burstcnt = tpm_get_burstcount(tpm);
845 for (; burstcnt > 0 && size < bufsiz; burstcnt--) {
846 buf[size++] = tpm_get8(tpm, TPM_DATA_FIFO);
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;
860 return (size);
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";
872 ASSERT(tpm != NULL && buf != NULL);
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;
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;
894 cmdresult = load32(buf, TPM_RETURN_OFFSET);
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;
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;
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);
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;
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;
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
943 tis_release_locality(tpm, tpm->locality, 0);
945 OUT:
946 tpm_set_ready(tpm);
947 tis_release_locality(tpm, tpm->locality, 0);
948 return (size);
952 * Send the data (TPM commands) to the Data IO register
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";
963 ASSERT(tpm != NULL && buf != NULL);
965 if (bufsiz == 0) {
966 #ifdef DEBUG
967 cmn_err(CE_WARN, "!%s: bufsiz arg is zero", myname);
968 #endif
969 return (DDI_FAILURE);
972 /* Put the TPM in ready state */
973 status = tis_get_status(tpm);
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;
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.
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;
1006 for (; burstcnt > 0 && count < bufsiz - 1; burstcnt--) {
1007 tpm_put8(tpm, TPM_DATA_FIFO, buf[count]);
1008 count++;
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;
1021 /* We can't exit the loop above unless we wrote bufsiz-1 bytes */
1023 /* Write last byte */
1024 tpm_put8(tpm, TPM_DATA_FIFO, buf[count]);
1025 count++;
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;
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;
1049 * Final step: Writing TPM_STS_GO to TPM_STS
1050 * register will actually send the command.
1052 tpm_put8(tpm, TPM_STS, TPM_STS_GO);
1054 /* Ordinal/Command_code is located in buf[6..9] */
1055 ordinal = load32(buf, TPM_COMMAND_CODE_OFFSET);
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);
1074 #endif
1075 goto FAIL;
1077 return (DDI_SUCCESS);
1079 FAIL:
1080 tpm_set_ready(tpm);
1081 tis_release_locality(tpm, tpm->locality, 0);
1082 return (ret);
1086 * Clear XrequestUse and Xactivelocality, where X is the current locality
1088 static void
1089 tis_release_locality(tpm_state_t *tpm, char locality, int force) {
1090 ASSERT(tpm != NULL && locality >= 0 && locality < 5);
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)) {
1097 * Writing 1 to active locality bit in TPM_ACCESS
1098 * register reliquishes the control of the locality
1100 tpm_put8(tpm, TPM_ACCESS, TPM_ACCESS_ACTIVE_LOCALITY);
1105 * Checks whether the given locality is active
1106 * Use TPM_ACCESS register and the masks TPM_ACCESS_VALID,TPM_ACTIVE_LOCALITY
1108 static int
1109 tis_check_active_locality(tpm_state_t *tpm, char locality) {
1110 uint8_t access_bits;
1111 uint8_t old_locality;
1113 ASSERT(tpm != NULL && locality >= 0 && locality < 5);
1115 old_locality = tpm->locality;
1116 tpm->locality = locality;
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);
1122 /* this was just a check, not a request to switch */
1123 tpm->locality = old_locality;
1125 if (access_bits == (TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) {
1126 return (DDI_SUCCESS);
1127 } else {
1128 return (DDI_FAILURE);
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";
1139 ASSERT(tpm != NULL && locality >= 0 && locality < 5);
1141 ret = tis_check_active_locality(tpm, locality);
1143 if (ret == DDI_SUCCESS) {
1144 /* Locality is already active */
1145 tpm->locality = locality;
1146 return (DDI_SUCCESS);
1149 tpm_put8(tpm, TPM_ACCESS, TPM_ACCESS_REQUEST_USE);
1150 timeout = ddi_get_lbolt() + tpm->timeout_a;
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);
1163 delay(tpm->timeout_poll);
1166 tpm->locality = locality;
1167 return (DDI_SUCCESS);
1170 /* Read the status register */
1171 static uint8_t
1172 tis_get_status(tpm_state_t *tpm) {
1173 return (tpm_get8(tpm, TPM_STS));
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;
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);
1192 delay(tpm->timeout_poll);
1194 return (DDI_SUCCESS);
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
1204 static int
1205 tis_init(tpm_state_t *tpm) {
1206 uint32_t intf_caps;
1207 int ret;
1208 char *myname = "tis_init";
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
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);
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).
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);
1230 /* Find out supported capabilities */
1231 intf_caps = tpm_get32(tpm, TPM_INTF_CAP);
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);
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);
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);
1254 * Before we start writing anything to TPM's registers,
1255 * make sure we are in locality 0
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 */
1264 tpm->timeout_poll = drv_usectohz(TPM_POLLING_TIMEOUT);
1265 tpm->intr_enabled = 0;
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);
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);
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);
1288 * Unless the TPM completes the test of its commands,
1289 * it can return an error when the untested commands are called
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);
1296 return (DDI_SUCCESS);
1300 * Module Entry points
1303 _init(void)
1305 int ret;
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);
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);
1323 return (ret);
1327 _info(struct modinfo *modinfop)
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
1336 return (ret);
1340 _fini()
1342 int ret;
1344 ret = mod_remove(&tpm_ml);
1345 if (ret != 0)
1346 return (ret);
1348 ddi_soft_state_fini(&statep);
1350 return (ret);
1352 /* End of driver configuration functions */
1354 static int
1355 tpm_resume(tpm_state_t *tpm)
1357 mutex_enter(&tpm->pm_mutex);
1358 if (!tpm->suspended) {
1359 mutex_exit(&tpm->pm_mutex);
1360 return (DDI_FAILURE);
1362 tpm->suspended = 0;
1363 cv_broadcast(&tpm->suspend_cv);
1364 mutex_exit(&tpm->pm_mutex);
1366 return (DDI_SUCCESS);
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
1374 #endif
1377 * Sun DDI/DDK entry points
1379 static int
1380 tpm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
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;
1390 ASSERT(dip != NULL);
1392 instance = ddi_get_instance(dip);
1393 if (instance < 0)
1394 return (DDI_FAILURE);
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);
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);
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);
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;
1437 /* Zeroize the flag, which is used to keep track of what is allocated */
1438 tpm->flags = 0;
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;
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;
1453 idx = 0;
1454 ret = ddi_dev_nregs(tpm->dip, &nregs);
1455 if (ret != DDI_SUCCESS)
1456 goto FAIL;
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).
1465 for (idx = 0; idx < nregs; idx++) {
1466 off_t regsize;
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;
1475 if (idx == nregs) {
1476 ret = DDI_FAILURE;
1477 goto FAIL;
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);
1484 if (ret != DDI_SUCCESS) {
1485 goto FAIL;
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
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;
1503 goto FAIL;
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);
1511 /* Set the suspend/resume property */
1512 (void) ddi_prop_update_string(DDI_DEV_T_NONE, dip,
1513 "pm-hardware-state", "needs-suspend-resume");
1515 mutex_enter(&tpm->pm_mutex);
1516 tpm->suspended = 0;
1517 mutex_exit(&tpm->pm_mutex);
1519 tpm->flags |= TPM_DID_MUTEX;
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;
1526 mutex_init(&tpm->iobuf_lock, NULL, MUTEX_DRIVER, NULL);
1527 tpm->flags |= TPM_DID_IO_MUTEX;
1529 cv_init(&tpm->iobuf_cv, NULL, CV_DRIVER, NULL);
1530 tpm->flags |= TPM_DID_IO_CV;
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;
1541 tpm->flags |= TPM_DIDMINOR;
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
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;
1558 return (DDI_FAILURE);
1562 * Called by tpm_detach and tpm_attach (only on failure)
1563 * Free up the resources that are allocated
1565 static void
1566 tpm_cleanup(dev_info_t *dip, tpm_state_t *tpm)
1568 if (tpm == NULL)
1569 return;
1571 #ifdef KCF_TPM_RNG_PROVIDER
1572 (void) tpmrng_unregister(tpm);
1573 #endif
1575 #ifdef sun4v
1576 if (tpm->flags & TPM_HSVC_REGISTERED) {
1577 (void) hsvc_unregister(&hsvc_tpm);
1578 tpm->flags &= ~(TPM_HSVC_REGISTERED);
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);
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);
1592 if (tpm->flags & TPM_DID_IO_MUTEX) {
1593 mutex_destroy(&tpm->iobuf_lock);
1594 tpm->flags &= ~(TPM_DID_IO_MUTEX);
1596 if (tpm->flags & TPM_DID_IO_CV) {
1597 cv_destroy(&tpm->iobuf_cv);
1598 tpm->flags &= ~(TPM_DID_IO_CV);
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);
1606 if (tpm->flags & TPM_DIDMINOR) {
1607 /* Remove minor node */
1608 ddi_remove_minor_node(dip, NULL);
1609 tpm->flags &= ~(TPM_DIDMINOR);
1613 static int
1614 tpm_suspend(tpm_state_t *tpm)
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);
1623 tpm->suspended = 1;
1624 mutex_exit(&tpm->pm_mutex);
1626 return (DDI_SUCCESS);
1629 static int
1630 tpm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
1632 char *myname = "tpm_detach";
1633 int instance;
1634 tpm_state_t *tpm;
1636 ASSERT(dip != NULL);
1638 instance = ddi_get_instance(dip);
1639 if (instance < 0)
1640 return (DDI_FAILURE);
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);
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);
1663 /* Since we are freeing tpm structure, we need to gain the lock */
1664 tpm_cleanup(dip, tpm);
1666 /* Free the soft state */
1667 ddi_soft_state_free(statep, instance);
1668 tpm = NULL;
1670 return (DDI_SUCCESS);
1673 /*ARGSUSED*/
1674 static int
1675 tpm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
1677 char *myname = "tpm_getinfo";
1678 int instance;
1679 tpm_state_t *tpm;
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);
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);
1703 return (DDI_SUCCESS);
1707 * Driver entry points
1710 /*ARGSUSED*/
1711 static int
1712 tpm_open(dev_t *devp, int flag, int otyp, cred_t *cred)
1714 char *myname = "tpm_open";
1715 int instance;
1716 tpm_state_t *tpm;
1718 ASSERT(devp != NULL);
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);
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);
1735 TPM_EXCLUSIVE_LOCK(tpm);
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);
1747 /* The device is free so mark it busy */
1748 tpm->dev_held = 1;
1749 mutex_exit(&tpm->dev_lock);
1751 return (0);
1754 /*ARGSUSED*/
1755 static int
1756 tpm_close(dev_t dev, int flag, int otyp, cred_t *cred)
1758 char *myname = "tpm_close";
1759 int instance;
1760 tpm_state_t *tpm;
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);
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);
1777 TPM_EXCLUSIVE_LOCK(tpm);
1779 ASSERT(tpm->dev_held);
1781 mutex_enter(&tpm->dev_lock);
1782 ASSERT(mutex_owned(&tpm->dev_lock));
1783 tpm->dev_held = 0;
1784 mutex_exit(&tpm->dev_lock);
1786 return (0);
1789 /*ARGSUSED*/
1790 static int
1791 tpm_read(dev_t dev, struct uio *uiop, cred_t *credp)
1793 int ret;
1794 uint32_t size;
1795 char *myname = "tpm_read";
1796 int instance;
1797 tpm_state_t *tpm;
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);
1807 if (uiop == NULL) {
1808 #ifdef DEBUG
1809 cmn_err(CE_WARN, "!%s: passed in uiop is NULL", myname);
1810 #endif
1811 return (EFAULT);
1814 TPM_EXCLUSIVE_LOCK(tpm);
1816 /* Receive the data after requiring the lock */
1817 ret = tpm_io_lock(tpm);
1819 /* Timeout reached */
1820 if (ret)
1821 return (ret);
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;
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;
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;
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;
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);
1869 return (ret);
1872 /*ARGSUSED*/
1873 static int
1874 tpm_write(dev_t dev, struct uio *uiop, cred_t *credp)
1876 int ret;
1877 size_t len;
1878 uint32_t size;
1879 char *myname = "tpm_write";
1880 int instance;
1881 tpm_state_t *tpm;
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);
1892 if (uiop == NULL) {
1893 #ifdef DEBUG
1894 cmn_err(CE_WARN, "!%s: passed in uiop is NULL", myname);
1895 #endif
1896 return (EFAULT);
1899 TPM_EXCLUSIVE_LOCK(tpm);
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);
1909 /* Get the lock for using iobuf */
1910 ret = tpm_io_lock(tpm);
1911 /* Timeout Reached */
1912 if (ret)
1913 return (ret);
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;
1926 /* Get the buffersize from the command buffer structure */
1927 size = load32(tpm->iobuf, TPM_PARAMSIZE_OFFSET);
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;
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);
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;
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;
1962 /* Zeroize the buffer... */
1963 bzero(tpm->iobuf, tpm->bufsize);
1964 ret = DDI_SUCCESS;
1965 OUT:
1966 tpm_unlock(tpm);
1967 return (ret);
1971 * This is to deal with the contentions for the iobuf
1973 static inline int
1974 tpm_io_lock(tpm_state_t *tpm)
1976 int ret;
1977 clock_t timeout;
1979 mutex_enter(&tpm->iobuf_lock);
1980 ASSERT(mutex_owned(&tpm->iobuf_lock));
1982 timeout = ddi_get_lbolt() + drv_usectohz(TPM_IO_TIMEOUT);
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);
1996 tpm->iobuf_inuse = 1;
1997 mutex_exit(&tpm->iobuf_lock);
1998 return (0);
2002 * This is to deal with the contentions for the iobuf
2004 static inline void
2005 tpm_unlock(tpm_state_t *tpm)
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);
2015 #ifdef KCF_TPM_RNG_PROVIDER
2017 * Random number generator entry points
2019 static void
2020 strncpy_spacepad(uchar_t *s1, char *s2, int n)
2022 int s2len = strlen(s2);
2023 (void) strncpy((char *)s1, s2, n);
2024 if (s2len < n)
2025 (void) memset(s1 + s2len, ' ', n - s2len);
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)
2034 tpm_state_t *tpm = (tpm_state_t *)prov;
2035 char buf[64];
2037 if (tpm == NULL)
2038 return (DDI_FAILURE);
2040 strncpy_spacepad(ext_info->ei_manufacturerID,
2041 (char *)tpm->vers_info.tpmVendorID,
2042 sizeof (ext_info->ei_manufacturerID));
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));
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;
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;
2066 (void) snprintf(buf, sizeof (buf), "tpmrng TPM RNG");
2068 strncpy_spacepad(ext_info->ei_label, buf,
2069 sizeof (ext_info->ei_label));
2070 #undef BUFSZ
2071 return (CRYPTO_SUCCESS);
2075 static int
2076 tpmrng_register(tpm_state_t *tpm)
2078 int ret;
2079 char ID[64];
2080 crypto_mech_name_t *rngmech;
2082 ASSERT(tpm != NULL);
2084 (void) snprintf(ID, sizeof (ID), "tpmrng %s", IDENT_TPMRNG);
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;
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);
2096 crypto_provider_notification(tpm->n_prov, CRYPTO_PROVIDER_READY);
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);
2109 static int
2110 tpmrng_unregister(tpm_state_t *tpm)
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);
2120 return (DDI_SUCCESS);
2123 /*ARGSUSED*/
2124 static void
2125 tpmrng_provider_status(crypto_provider_handle_t provider, uint_t *status)
2127 *status = CRYPTO_PROVIDER_READY;
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)
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) */
2146 uint32_t buflen;
2148 if (len == 0 || len > 255 || buf == NULL)
2149 return (CRYPTO_ARGUMENTS_BAD);
2151 tpm = (tpm_state_t *)provider;
2152 if (tpm == NULL)
2153 return (CRYPTO_INVALID_CONTEXT);
2155 /* Acquire lock for exclusive use of TPM */
2156 TPM_EXCLUSIVE_LOCK(tpm);
2158 ret = tpm_io_lock(tpm);
2159 /* Timeout reached */
2160 if (ret)
2161 return (CRYPTO_BUSY);
2163 /* TPM only handles 32 bit length, so truncate if too big. */
2164 len32 = (uint32_t)len;
2165 buflen = len32 + 14;
2167 /* The length must be in network order */
2168 buflen = htonl(buflen);
2169 bcopy(&buflen, cmdbuf + 2, sizeof (uint32_t));
2171 /* Convert it back */
2172 buflen = ntohl(buflen);
2174 /* length must be in network order */
2175 len32 = htonl(len32);
2176 bcopy(&len32, cmdbuf + 10, sizeof (uint32_t));
2178 /* convert it back */
2179 len32 = ntohl(len32);
2181 bcopy(buf, cmdbuf + 14, len32);
2183 ret = itpm_command(tpm, cmdbuf, buflen);
2184 tpm_unlock(tpm);
2186 if (ret != DDI_SUCCESS) {
2187 #ifdef DEBUG
2188 cmn_err(CE_WARN, "!tpmrng_seed_random failed");
2189 #endif
2190 return (CRYPTO_FAILED);
2193 return (CRYPTO_SUCCESS);
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)
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
2209 uint8_t *cmdbuf = NULL;
2210 uint32_t len32 = (uint32_t)len;
2211 uint32_t buflen = len32 + sizeof (hdr);
2213 if (len == 0 || buf == NULL)
2214 return (CRYPTO_ARGUMENTS_BAD);
2216 tpm = (tpm_state_t *)provider;
2217 if (tpm == NULL)
2218 return (CRYPTO_INVALID_CONTEXT);
2220 TPM_EXCLUSIVE_LOCK(tpm);
2222 ret = tpm_io_lock(tpm);
2223 /* Timeout reached */
2224 if (ret)
2225 return (CRYPTO_BUSY);
2227 cmdbuf = kmem_zalloc(buflen, KM_SLEEP);
2228 bcopy(hdr, cmdbuf, sizeof (hdr));
2230 /* Length is written in network byte order */
2231 len32 = htonl(len32);
2232 bcopy(&len32, cmdbuf + 10, sizeof (uint32_t));
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);
2244 /* Find out how many bytes were really returned */
2245 len32 = load32(cmdbuf, 10);
2247 /* Copy the random bytes back to the callers buffer */
2248 bcopy(cmdbuf + 14, buf, len32);
2250 kmem_free(cmdbuf, buflen);
2251 tpm_unlock(tpm);
2253 return (CRYPTO_SUCCESS);
2255 #endif /* KCF_TPM_RNG_PROVIDER */