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 */