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