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