OLD | NEW |
(Empty) | |
| 1 /* |
| 2 * Copyright (C) 2011 Infineon Technologies |
| 3 * |
| 4 * Authors: |
| 5 * Peter Huewe <huewe.external@infineon.com> |
| 6 * |
| 7 * Description: |
| 8 * Device driver for TCG/TCPA TPM (trusted platform module). |
| 9 * Specifications at www.trustedcomputinggroup.org |
| 10 * |
| 11 * It is based on the Linux kernel driver tpm.c from Leendert van |
| 12 * Dorn, Dave Safford, Reiner Sailer, and Kyleen Hall. |
| 13 * |
| 14 * Version: 2.1.1 |
| 15 * |
| 16 * See file CREDITS for list of people who contributed to this |
| 17 * project. |
| 18 * |
| 19 * This program is free software; you can redistribute it and/or |
| 20 * modify it under the terms of the GNU General Public License as |
| 21 * published by the Free Software Foundation, version 2 of the |
| 22 * License. |
| 23 * |
| 24 * This program is distributed in the hope that it will be useful, |
| 25 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 27 * GNU General Public License for more details. |
| 28 * |
| 29 * You should have received a copy of the GNU General Public License |
| 30 * along with this program; if not, write to the Free Software |
| 31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, |
| 32 * MA 02111-1307 USA |
| 33 */ |
| 34 |
| 35 #include <malloc.h> |
| 36 #include "tpm.h" |
| 37 |
| 38 /* global structure for tpm chip data */ |
| 39 struct tpm_chip g_chip; |
| 40 |
| 41 enum tpm_duration { |
| 42 TPM_SHORT = 0, |
| 43 TPM_MEDIUM = 1, |
| 44 TPM_LONG = 2, |
| 45 TPM_UNDEFINED, |
| 46 }; |
| 47 |
| 48 #define TPM_MAX_ORDINAL 243 |
| 49 #define TPM_MAX_PROTECTED_ORDINAL 12 |
| 50 #define TPM_PROTECTED_ORDINAL_MASK 0xFF |
| 51 |
| 52 /* |
| 53 * Array with one entry per ordinal defining the maximum amount |
| 54 * of time the chip could take to return the result. The ordinal |
| 55 * designation of short, medium or long is defined in a table in |
| 56 * TCG Specification TPM Main Part 2 TPM Structures Section 17. The |
| 57 * values of the SHORT, MEDIUM, and LONG durations are retrieved |
| 58 * from the chip during initialization with a call to tpm_get_timeouts. |
| 59 */ |
| 60 static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = { |
| 61 TPM_UNDEFINED, /* 0 */ |
| 62 TPM_UNDEFINED, |
| 63 TPM_UNDEFINED, |
| 64 TPM_UNDEFINED, |
| 65 TPM_UNDEFINED, |
| 66 TPM_UNDEFINED, /* 5 */ |
| 67 TPM_UNDEFINED, |
| 68 TPM_UNDEFINED, |
| 69 TPM_UNDEFINED, |
| 70 TPM_UNDEFINED, |
| 71 TPM_SHORT, /* 10 */ |
| 72 TPM_SHORT, |
| 73 }; |
| 74 |
| 75 static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = { |
| 76 TPM_UNDEFINED, /* 0 */ |
| 77 TPM_UNDEFINED, |
| 78 TPM_UNDEFINED, |
| 79 TPM_UNDEFINED, |
| 80 TPM_UNDEFINED, |
| 81 TPM_UNDEFINED, /* 5 */ |
| 82 TPM_UNDEFINED, |
| 83 TPM_UNDEFINED, |
| 84 TPM_UNDEFINED, |
| 85 TPM_UNDEFINED, |
| 86 TPM_SHORT, /* 10 */ |
| 87 TPM_SHORT, |
| 88 TPM_MEDIUM, |
| 89 TPM_LONG, |
| 90 TPM_LONG, |
| 91 TPM_MEDIUM, /* 15 */ |
| 92 TPM_SHORT, |
| 93 TPM_SHORT, |
| 94 TPM_MEDIUM, |
| 95 TPM_LONG, |
| 96 TPM_SHORT, /* 20 */ |
| 97 TPM_SHORT, |
| 98 TPM_MEDIUM, |
| 99 TPM_MEDIUM, |
| 100 TPM_MEDIUM, |
| 101 TPM_SHORT, /* 25 */ |
| 102 TPM_SHORT, |
| 103 TPM_MEDIUM, |
| 104 TPM_SHORT, |
| 105 TPM_SHORT, |
| 106 TPM_MEDIUM, /* 30 */ |
| 107 TPM_LONG, |
| 108 TPM_MEDIUM, |
| 109 TPM_SHORT, |
| 110 TPM_SHORT, |
| 111 TPM_SHORT, /* 35 */ |
| 112 TPM_MEDIUM, |
| 113 TPM_MEDIUM, |
| 114 TPM_UNDEFINED, |
| 115 TPM_UNDEFINED, |
| 116 TPM_MEDIUM, /* 40 */ |
| 117 TPM_LONG, |
| 118 TPM_MEDIUM, |
| 119 TPM_SHORT, |
| 120 TPM_SHORT, |
| 121 TPM_SHORT, /* 45 */ |
| 122 TPM_SHORT, |
| 123 TPM_SHORT, |
| 124 TPM_SHORT, |
| 125 TPM_LONG, |
| 126 TPM_MEDIUM, /* 50 */ |
| 127 TPM_MEDIUM, |
| 128 TPM_UNDEFINED, |
| 129 TPM_UNDEFINED, |
| 130 TPM_UNDEFINED, |
| 131 TPM_UNDEFINED, /* 55 */ |
| 132 TPM_UNDEFINED, |
| 133 TPM_UNDEFINED, |
| 134 TPM_UNDEFINED, |
| 135 TPM_UNDEFINED, |
| 136 TPM_MEDIUM, /* 60 */ |
| 137 TPM_MEDIUM, |
| 138 TPM_MEDIUM, |
| 139 TPM_SHORT, |
| 140 TPM_SHORT, |
| 141 TPM_MEDIUM, /* 65 */ |
| 142 TPM_UNDEFINED, |
| 143 TPM_UNDEFINED, |
| 144 TPM_UNDEFINED, |
| 145 TPM_UNDEFINED, |
| 146 TPM_SHORT, /* 70 */ |
| 147 TPM_SHORT, |
| 148 TPM_UNDEFINED, |
| 149 TPM_UNDEFINED, |
| 150 TPM_UNDEFINED, |
| 151 TPM_UNDEFINED, /* 75 */ |
| 152 TPM_UNDEFINED, |
| 153 TPM_UNDEFINED, |
| 154 TPM_UNDEFINED, |
| 155 TPM_UNDEFINED, |
| 156 TPM_LONG, /* 80 */ |
| 157 TPM_UNDEFINED, |
| 158 TPM_MEDIUM, |
| 159 TPM_LONG, |
| 160 TPM_SHORT, |
| 161 TPM_UNDEFINED, /* 85 */ |
| 162 TPM_UNDEFINED, |
| 163 TPM_UNDEFINED, |
| 164 TPM_UNDEFINED, |
| 165 TPM_UNDEFINED, |
| 166 TPM_SHORT, /* 90 */ |
| 167 TPM_SHORT, |
| 168 TPM_SHORT, |
| 169 TPM_SHORT, |
| 170 TPM_SHORT, |
| 171 TPM_UNDEFINED, /* 95 */ |
| 172 TPM_UNDEFINED, |
| 173 TPM_UNDEFINED, |
| 174 TPM_UNDEFINED, |
| 175 TPM_UNDEFINED, |
| 176 TPM_MEDIUM, /* 100 */ |
| 177 TPM_SHORT, |
| 178 TPM_SHORT, |
| 179 TPM_UNDEFINED, |
| 180 TPM_UNDEFINED, |
| 181 TPM_UNDEFINED, /* 105 */ |
| 182 TPM_UNDEFINED, |
| 183 TPM_UNDEFINED, |
| 184 TPM_UNDEFINED, |
| 185 TPM_UNDEFINED, |
| 186 TPM_SHORT, /* 110 */ |
| 187 TPM_SHORT, |
| 188 TPM_SHORT, |
| 189 TPM_SHORT, |
| 190 TPM_SHORT, |
| 191 TPM_SHORT, /* 115 */ |
| 192 TPM_SHORT, |
| 193 TPM_SHORT, |
| 194 TPM_UNDEFINED, |
| 195 TPM_UNDEFINED, |
| 196 TPM_LONG, /* 120 */ |
| 197 TPM_LONG, |
| 198 TPM_MEDIUM, |
| 199 TPM_UNDEFINED, |
| 200 TPM_SHORT, |
| 201 TPM_SHORT, /* 125 */ |
| 202 TPM_SHORT, |
| 203 TPM_LONG, |
| 204 TPM_SHORT, |
| 205 TPM_SHORT, |
| 206 TPM_SHORT, /* 130 */ |
| 207 TPM_MEDIUM, |
| 208 TPM_UNDEFINED, |
| 209 TPM_SHORT, |
| 210 TPM_MEDIUM, |
| 211 TPM_UNDEFINED, /* 135 */ |
| 212 TPM_UNDEFINED, |
| 213 TPM_UNDEFINED, |
| 214 TPM_UNDEFINED, |
| 215 TPM_UNDEFINED, |
| 216 TPM_SHORT, /* 140 */ |
| 217 TPM_SHORT, |
| 218 TPM_UNDEFINED, |
| 219 TPM_UNDEFINED, |
| 220 TPM_UNDEFINED, |
| 221 TPM_UNDEFINED, /* 145 */ |
| 222 TPM_UNDEFINED, |
| 223 TPM_UNDEFINED, |
| 224 TPM_UNDEFINED, |
| 225 TPM_UNDEFINED, |
| 226 TPM_SHORT, /* 150 */ |
| 227 TPM_MEDIUM, |
| 228 TPM_MEDIUM, |
| 229 TPM_SHORT, |
| 230 TPM_SHORT, |
| 231 TPM_UNDEFINED, /* 155 */ |
| 232 TPM_UNDEFINED, |
| 233 TPM_UNDEFINED, |
| 234 TPM_UNDEFINED, |
| 235 TPM_UNDEFINED, |
| 236 TPM_SHORT, /* 160 */ |
| 237 TPM_SHORT, |
| 238 TPM_SHORT, |
| 239 TPM_SHORT, |
| 240 TPM_UNDEFINED, |
| 241 TPM_UNDEFINED, /* 165 */ |
| 242 TPM_UNDEFINED, |
| 243 TPM_UNDEFINED, |
| 244 TPM_UNDEFINED, |
| 245 TPM_UNDEFINED, |
| 246 TPM_LONG, /* 170 */ |
| 247 TPM_UNDEFINED, |
| 248 TPM_UNDEFINED, |
| 249 TPM_UNDEFINED, |
| 250 TPM_UNDEFINED, |
| 251 TPM_UNDEFINED, /* 175 */ |
| 252 TPM_UNDEFINED, |
| 253 TPM_UNDEFINED, |
| 254 TPM_UNDEFINED, |
| 255 TPM_UNDEFINED, |
| 256 TPM_MEDIUM, /* 180 */ |
| 257 TPM_SHORT, |
| 258 TPM_MEDIUM, |
| 259 TPM_MEDIUM, |
| 260 TPM_MEDIUM, |
| 261 TPM_MEDIUM, /* 185 */ |
| 262 TPM_SHORT, |
| 263 TPM_UNDEFINED, |
| 264 TPM_UNDEFINED, |
| 265 TPM_UNDEFINED, |
| 266 TPM_UNDEFINED, /* 190 */ |
| 267 TPM_UNDEFINED, |
| 268 TPM_UNDEFINED, |
| 269 TPM_UNDEFINED, |
| 270 TPM_UNDEFINED, |
| 271 TPM_UNDEFINED, /* 195 */ |
| 272 TPM_UNDEFINED, |
| 273 TPM_UNDEFINED, |
| 274 TPM_UNDEFINED, |
| 275 TPM_UNDEFINED, |
| 276 TPM_SHORT, /* 200 */ |
| 277 TPM_UNDEFINED, |
| 278 TPM_UNDEFINED, |
| 279 TPM_UNDEFINED, |
| 280 TPM_SHORT, |
| 281 TPM_SHORT, /* 205 */ |
| 282 TPM_SHORT, |
| 283 TPM_SHORT, |
| 284 TPM_SHORT, |
| 285 TPM_SHORT, |
| 286 TPM_MEDIUM, /* 210 */ |
| 287 TPM_UNDEFINED, |
| 288 TPM_MEDIUM, |
| 289 TPM_MEDIUM, |
| 290 TPM_MEDIUM, |
| 291 TPM_UNDEFINED, /* 215 */ |
| 292 TPM_MEDIUM, |
| 293 TPM_UNDEFINED, |
| 294 TPM_UNDEFINED, |
| 295 TPM_SHORT, |
| 296 TPM_SHORT, /* 220 */ |
| 297 TPM_SHORT, |
| 298 TPM_SHORT, |
| 299 TPM_SHORT, |
| 300 TPM_SHORT, |
| 301 TPM_UNDEFINED, /* 225 */ |
| 302 TPM_UNDEFINED, |
| 303 TPM_UNDEFINED, |
| 304 TPM_UNDEFINED, |
| 305 TPM_UNDEFINED, |
| 306 TPM_SHORT, /* 230 */ |
| 307 TPM_LONG, |
| 308 TPM_MEDIUM, |
| 309 TPM_UNDEFINED, |
| 310 TPM_UNDEFINED, |
| 311 TPM_UNDEFINED, /* 235 */ |
| 312 TPM_UNDEFINED, |
| 313 TPM_UNDEFINED, |
| 314 TPM_UNDEFINED, |
| 315 TPM_UNDEFINED, |
| 316 TPM_SHORT, /* 240 */ |
| 317 TPM_UNDEFINED, |
| 318 TPM_MEDIUM, |
| 319 }; |
| 320 |
| 321 /* |
| 322 * Returns max number of milliseconds to wait |
| 323 */ |
| 324 unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal) |
| 325 { |
| 326 int duration_idx = TPM_UNDEFINED; |
| 327 int duration = 0; |
| 328 |
| 329 if (ordinal < TPM_MAX_ORDINAL) |
| 330 duration_idx = tpm_ordinal_duration[ordinal]; |
| 331 else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) < |
| 332 TPM_MAX_PROTECTED_ORDINAL) |
| 333 duration_idx = |
| 334 tpm_protected_ordinal_duration[ordinal & |
| 335 TPM_PROTECTED_ORDINAL_MASK]; |
| 336 |
| 337 if (duration_idx != TPM_UNDEFINED) |
| 338 duration = chip->vendor.duration[duration_idx]; |
| 339 if (duration <= 0) |
| 340 return 2 * 60 * HZ; /*two minutes timeout*/ |
| 341 else |
| 342 return duration; |
| 343 } |
| 344 |
| 345 #define TPM_CMD_COUNT_BYTE 2 |
| 346 #define TPM_CMD_ORDINAL_BYTE 6 |
| 347 |
| 348 ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz) |
| 349 { |
| 350 ssize_t rc; |
| 351 u32 count, ordinal; |
| 352 unsigned long start, stop; |
| 353 |
| 354 struct tpm_chip *chip = &g_chip; |
| 355 |
| 356 /* switch endianess: big->little */ |
| 357 count = get_unaligned_be32(buf + TPM_CMD_COUNT_BYTE); |
| 358 ordinal = get_unaligned_be32(buf + TPM_CMD_ORDINAL_BYTE); |
| 359 |
| 360 if (count == 0) { |
| 361 dev_err(chip->dev, "no data\n"); |
| 362 return -ENODATA; |
| 363 } |
| 364 if (count > bufsiz) { |
| 365 dev_err(chip->dev, |
| 366 "invalid count value %x %zx\n", count, bufsiz); |
| 367 return -E2BIG; |
| 368 } |
| 369 |
| 370 rc = chip->vendor.send(chip, (u8 *) buf, count); |
| 371 if (rc < 0) { |
| 372 dev_err(chip->dev, "tpm_transmit: tpm_send: error %zd\n", rc); |
| 373 goto out; |
| 374 } |
| 375 |
| 376 if (chip->vendor.irq) |
| 377 goto out_recv; |
| 378 |
| 379 start = get_timer(0); |
| 380 stop = tpm_calc_ordinal_duration(chip, ordinal); |
| 381 do { |
| 382 dbg_printf("waiting for status...\n"); |
| 383 u8 status = chip->vendor.status(chip); |
| 384 if ((status & chip->vendor.req_complete_mask) == |
| 385 chip->vendor.req_complete_val) { |
| 386 dbg_printf("...got it;\n"); |
| 387 goto out_recv; |
| 388 } |
| 389 |
| 390 if ((status == chip->vendor.req_canceled)) { |
| 391 dev_err(chip->dev, "Operation Canceled\n"); |
| 392 rc = -ECANCELED; |
| 393 goto out; |
| 394 } |
| 395 msleep(TPM_TIMEOUT); |
| 396 } while (get_timer(start) < stop); |
| 397 |
| 398 chip->vendor.cancel(chip); |
| 399 dev_err(chip->dev, "Operation Timed out\n"); |
| 400 rc = -ETIME; |
| 401 goto out; |
| 402 |
| 403 out_recv: |
| 404 |
| 405 dbg_printf("out_recv: reading response...\n"); |
| 406 rc = chip->vendor.recv(chip, (u8 *) buf, TPM_BUFSIZE); |
| 407 if (rc < 0) |
| 408 dev_err(chip->dev, "tpm_transmit: tpm_recv: error %zd\n", rc); |
| 409 out: |
| 410 return rc; |
| 411 } |
| 412 |
| 413 #define TPM_ERROR_SIZE 10 |
| 414 |
| 415 enum tpm_capabilities { |
| 416 TPM_CAP_PROP = cpu_to_be32(5), |
| 417 }; |
| 418 |
| 419 enum tpm_sub_capabilities { |
| 420 TPM_CAP_PROP_TIS_TIMEOUT = cpu_to_be32(0x115), |
| 421 TPM_CAP_PROP_TIS_DURATION = cpu_to_be32(0x120), |
| 422 }; |
| 423 |
| 424 static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd, |
| 425 int len, const char *desc) |
| 426 { |
| 427 int err; |
| 428 |
| 429 len = tpm_transmit((u8 *) cmd, len); |
| 430 if (len < 0) |
| 431 return len; |
| 432 if (len == TPM_ERROR_SIZE) { |
| 433 err = be32_to_cpu(cmd->header.out.return_code); |
| 434 dev_dbg(chip->dev, "A TPM error (%d) occurred %s\n", err, desc); |
| 435 return err; |
| 436 } |
| 437 return 0; |
| 438 } |
| 439 |
| 440 struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *entry) |
| 441 { |
| 442 struct tpm_chip *chip; |
| 443 |
| 444 /* Driver specific per-device data */ |
| 445 chip = &g_chip; |
| 446 memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific)); |
| 447 chip->is_open = 1; |
| 448 |
| 449 return chip; |
| 450 } |
| 451 |
| 452 int tpm_open(uint32_t dev_addr) |
| 453 { |
| 454 int rc; |
| 455 if (g_chip.is_open) |
| 456 return -EBUSY; |
| 457 rc = tpm_vendor_init(dev_addr); |
| 458 if (rc < 0) |
| 459 g_chip.is_open = 0; |
| 460 return rc; |
| 461 } |
| 462 |
| 463 void tpm_close(void) |
| 464 { |
| 465 if (g_chip.is_open) { |
| 466 tpm_vendor_cleanup(&g_chip); |
| 467 g_chip.is_open = 0; |
| 468 } |
| 469 } |
OLD | NEW |