tpm.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  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. #include <config.h>
  35. #include <common.h>
  36. #include <dm.h>
  37. #include <linux/compiler.h>
  38. #include <fdtdec.h>
  39. #include <i2c.h>
  40. #include <tpm.h>
  41. #include <asm-generic/errno.h>
  42. #include <linux/types.h>
  43. #include <linux/unaligned/be_byteshift.h>
  44. #include "tpm_private.h"
  45. DECLARE_GLOBAL_DATA_PTR;
  46. /* TPM configuration */
  47. struct tpm {
  48. #ifdef CONFIG_DM_I2C
  49. struct udevice *dev;
  50. #else
  51. int i2c_bus;
  52. int slave_addr;
  53. int old_bus;
  54. #endif
  55. char inited;
  56. } tpm;
  57. /* Global structure for tpm chip data */
  58. static struct tpm_chip g_chip;
  59. enum tpm_duration {
  60. TPM_SHORT = 0,
  61. TPM_MEDIUM = 1,
  62. TPM_LONG = 2,
  63. TPM_UNDEFINED,
  64. };
  65. /* Extended error numbers from linux (see errno.h) */
  66. #define ECANCELED 125 /* Operation Canceled */
  67. /* Timer frequency. Corresponds to msec timer resolution*/
  68. #define HZ 1000
  69. #define TPM_MAX_ORDINAL 243
  70. #define TPM_MAX_PROTECTED_ORDINAL 12
  71. #define TPM_PROTECTED_ORDINAL_MASK 0xFF
  72. #define TPM_CMD_COUNT_BYTE 2
  73. #define TPM_CMD_ORDINAL_BYTE 6
  74. /*
  75. * Array with one entry per ordinal defining the maximum amount
  76. * of time the chip could take to return the result. The ordinal
  77. * designation of short, medium or long is defined in a table in
  78. * TCG Specification TPM Main Part 2 TPM Structures Section 17. The
  79. * values of the SHORT, MEDIUM, and LONG durations are retrieved
  80. * from the chip during initialization with a call to tpm_get_timeouts.
  81. */
  82. static const u8 tpm_protected_ordinal_duration[TPM_MAX_PROTECTED_ORDINAL] = {
  83. TPM_UNDEFINED, /* 0 */
  84. TPM_UNDEFINED,
  85. TPM_UNDEFINED,
  86. TPM_UNDEFINED,
  87. TPM_UNDEFINED,
  88. TPM_UNDEFINED, /* 5 */
  89. TPM_UNDEFINED,
  90. TPM_UNDEFINED,
  91. TPM_UNDEFINED,
  92. TPM_UNDEFINED,
  93. TPM_SHORT, /* 10 */
  94. TPM_SHORT,
  95. };
  96. static const u8 tpm_ordinal_duration[TPM_MAX_ORDINAL] = {
  97. TPM_UNDEFINED, /* 0 */
  98. TPM_UNDEFINED,
  99. TPM_UNDEFINED,
  100. TPM_UNDEFINED,
  101. TPM_UNDEFINED,
  102. TPM_UNDEFINED, /* 5 */
  103. TPM_UNDEFINED,
  104. TPM_UNDEFINED,
  105. TPM_UNDEFINED,
  106. TPM_UNDEFINED,
  107. TPM_SHORT, /* 10 */
  108. TPM_SHORT,
  109. TPM_MEDIUM,
  110. TPM_LONG,
  111. TPM_LONG,
  112. TPM_MEDIUM, /* 15 */
  113. TPM_SHORT,
  114. TPM_SHORT,
  115. TPM_MEDIUM,
  116. TPM_LONG,
  117. TPM_SHORT, /* 20 */
  118. TPM_SHORT,
  119. TPM_MEDIUM,
  120. TPM_MEDIUM,
  121. TPM_MEDIUM,
  122. TPM_SHORT, /* 25 */
  123. TPM_SHORT,
  124. TPM_MEDIUM,
  125. TPM_SHORT,
  126. TPM_SHORT,
  127. TPM_MEDIUM, /* 30 */
  128. TPM_LONG,
  129. TPM_MEDIUM,
  130. TPM_SHORT,
  131. TPM_SHORT,
  132. TPM_SHORT, /* 35 */
  133. TPM_MEDIUM,
  134. TPM_MEDIUM,
  135. TPM_UNDEFINED,
  136. TPM_UNDEFINED,
  137. TPM_MEDIUM, /* 40 */
  138. TPM_LONG,
  139. TPM_MEDIUM,
  140. TPM_SHORT,
  141. TPM_SHORT,
  142. TPM_SHORT, /* 45 */
  143. TPM_SHORT,
  144. TPM_SHORT,
  145. TPM_SHORT,
  146. TPM_LONG,
  147. TPM_MEDIUM, /* 50 */
  148. TPM_MEDIUM,
  149. TPM_UNDEFINED,
  150. TPM_UNDEFINED,
  151. TPM_UNDEFINED,
  152. TPM_UNDEFINED, /* 55 */
  153. TPM_UNDEFINED,
  154. TPM_UNDEFINED,
  155. TPM_UNDEFINED,
  156. TPM_UNDEFINED,
  157. TPM_MEDIUM, /* 60 */
  158. TPM_MEDIUM,
  159. TPM_MEDIUM,
  160. TPM_SHORT,
  161. TPM_SHORT,
  162. TPM_MEDIUM, /* 65 */
  163. TPM_UNDEFINED,
  164. TPM_UNDEFINED,
  165. TPM_UNDEFINED,
  166. TPM_UNDEFINED,
  167. TPM_SHORT, /* 70 */
  168. TPM_SHORT,
  169. TPM_UNDEFINED,
  170. TPM_UNDEFINED,
  171. TPM_UNDEFINED,
  172. TPM_UNDEFINED, /* 75 */
  173. TPM_UNDEFINED,
  174. TPM_UNDEFINED,
  175. TPM_UNDEFINED,
  176. TPM_UNDEFINED,
  177. TPM_LONG, /* 80 */
  178. TPM_UNDEFINED,
  179. TPM_MEDIUM,
  180. TPM_LONG,
  181. TPM_SHORT,
  182. TPM_UNDEFINED, /* 85 */
  183. TPM_UNDEFINED,
  184. TPM_UNDEFINED,
  185. TPM_UNDEFINED,
  186. TPM_UNDEFINED,
  187. TPM_SHORT, /* 90 */
  188. TPM_SHORT,
  189. TPM_SHORT,
  190. TPM_SHORT,
  191. TPM_SHORT,
  192. TPM_UNDEFINED, /* 95 */
  193. TPM_UNDEFINED,
  194. TPM_UNDEFINED,
  195. TPM_UNDEFINED,
  196. TPM_UNDEFINED,
  197. TPM_MEDIUM, /* 100 */
  198. TPM_SHORT,
  199. TPM_SHORT,
  200. TPM_UNDEFINED,
  201. TPM_UNDEFINED,
  202. TPM_UNDEFINED, /* 105 */
  203. TPM_UNDEFINED,
  204. TPM_UNDEFINED,
  205. TPM_UNDEFINED,
  206. TPM_UNDEFINED,
  207. TPM_SHORT, /* 110 */
  208. TPM_SHORT,
  209. TPM_SHORT,
  210. TPM_SHORT,
  211. TPM_SHORT,
  212. TPM_SHORT, /* 115 */
  213. TPM_SHORT,
  214. TPM_SHORT,
  215. TPM_UNDEFINED,
  216. TPM_UNDEFINED,
  217. TPM_LONG, /* 120 */
  218. TPM_LONG,
  219. TPM_MEDIUM,
  220. TPM_UNDEFINED,
  221. TPM_SHORT,
  222. TPM_SHORT, /* 125 */
  223. TPM_SHORT,
  224. TPM_LONG,
  225. TPM_SHORT,
  226. TPM_SHORT,
  227. TPM_SHORT, /* 130 */
  228. TPM_MEDIUM,
  229. TPM_UNDEFINED,
  230. TPM_SHORT,
  231. TPM_MEDIUM,
  232. TPM_UNDEFINED, /* 135 */
  233. TPM_UNDEFINED,
  234. TPM_UNDEFINED,
  235. TPM_UNDEFINED,
  236. TPM_UNDEFINED,
  237. TPM_SHORT, /* 140 */
  238. TPM_SHORT,
  239. TPM_UNDEFINED,
  240. TPM_UNDEFINED,
  241. TPM_UNDEFINED,
  242. TPM_UNDEFINED, /* 145 */
  243. TPM_UNDEFINED,
  244. TPM_UNDEFINED,
  245. TPM_UNDEFINED,
  246. TPM_UNDEFINED,
  247. TPM_SHORT, /* 150 */
  248. TPM_MEDIUM,
  249. TPM_MEDIUM,
  250. TPM_SHORT,
  251. TPM_SHORT,
  252. TPM_UNDEFINED, /* 155 */
  253. TPM_UNDEFINED,
  254. TPM_UNDEFINED,
  255. TPM_UNDEFINED,
  256. TPM_UNDEFINED,
  257. TPM_SHORT, /* 160 */
  258. TPM_SHORT,
  259. TPM_SHORT,
  260. TPM_SHORT,
  261. TPM_UNDEFINED,
  262. TPM_UNDEFINED, /* 165 */
  263. TPM_UNDEFINED,
  264. TPM_UNDEFINED,
  265. TPM_UNDEFINED,
  266. TPM_UNDEFINED,
  267. TPM_LONG, /* 170 */
  268. TPM_UNDEFINED,
  269. TPM_UNDEFINED,
  270. TPM_UNDEFINED,
  271. TPM_UNDEFINED,
  272. TPM_UNDEFINED, /* 175 */
  273. TPM_UNDEFINED,
  274. TPM_UNDEFINED,
  275. TPM_UNDEFINED,
  276. TPM_UNDEFINED,
  277. TPM_MEDIUM, /* 180 */
  278. TPM_SHORT,
  279. TPM_MEDIUM,
  280. TPM_MEDIUM,
  281. TPM_MEDIUM,
  282. TPM_MEDIUM, /* 185 */
  283. TPM_SHORT,
  284. TPM_UNDEFINED,
  285. TPM_UNDEFINED,
  286. TPM_UNDEFINED,
  287. TPM_UNDEFINED, /* 190 */
  288. TPM_UNDEFINED,
  289. TPM_UNDEFINED,
  290. TPM_UNDEFINED,
  291. TPM_UNDEFINED,
  292. TPM_UNDEFINED, /* 195 */
  293. TPM_UNDEFINED,
  294. TPM_UNDEFINED,
  295. TPM_UNDEFINED,
  296. TPM_UNDEFINED,
  297. TPM_SHORT, /* 200 */
  298. TPM_UNDEFINED,
  299. TPM_UNDEFINED,
  300. TPM_UNDEFINED,
  301. TPM_SHORT,
  302. TPM_SHORT, /* 205 */
  303. TPM_SHORT,
  304. TPM_SHORT,
  305. TPM_SHORT,
  306. TPM_SHORT,
  307. TPM_MEDIUM, /* 210 */
  308. TPM_UNDEFINED,
  309. TPM_MEDIUM,
  310. TPM_MEDIUM,
  311. TPM_MEDIUM,
  312. TPM_UNDEFINED, /* 215 */
  313. TPM_MEDIUM,
  314. TPM_UNDEFINED,
  315. TPM_UNDEFINED,
  316. TPM_SHORT,
  317. TPM_SHORT, /* 220 */
  318. TPM_SHORT,
  319. TPM_SHORT,
  320. TPM_SHORT,
  321. TPM_SHORT,
  322. TPM_UNDEFINED, /* 225 */
  323. TPM_UNDEFINED,
  324. TPM_UNDEFINED,
  325. TPM_UNDEFINED,
  326. TPM_UNDEFINED,
  327. TPM_SHORT, /* 230 */
  328. TPM_LONG,
  329. TPM_MEDIUM,
  330. TPM_UNDEFINED,
  331. TPM_UNDEFINED,
  332. TPM_UNDEFINED, /* 235 */
  333. TPM_UNDEFINED,
  334. TPM_UNDEFINED,
  335. TPM_UNDEFINED,
  336. TPM_UNDEFINED,
  337. TPM_SHORT, /* 240 */
  338. TPM_UNDEFINED,
  339. TPM_MEDIUM,
  340. };
  341. /* Returns max number of milliseconds to wait */
  342. static unsigned long tpm_calc_ordinal_duration(struct tpm_chip *chip,
  343. u32 ordinal)
  344. {
  345. int duration_idx = TPM_UNDEFINED;
  346. int duration = 0;
  347. if (ordinal < TPM_MAX_ORDINAL) {
  348. duration_idx = tpm_ordinal_duration[ordinal];
  349. } else if ((ordinal & TPM_PROTECTED_ORDINAL_MASK) <
  350. TPM_MAX_PROTECTED_ORDINAL) {
  351. duration_idx = tpm_protected_ordinal_duration[
  352. ordinal & TPM_PROTECTED_ORDINAL_MASK];
  353. }
  354. if (duration_idx != TPM_UNDEFINED)
  355. duration = chip->vendor.duration[duration_idx];
  356. if (duration <= 0)
  357. return 2 * 60 * HZ; /* Two minutes timeout */
  358. else
  359. return duration;
  360. }
  361. static ssize_t tpm_transmit(const unsigned char *buf, size_t bufsiz)
  362. {
  363. int rc;
  364. u32 count, ordinal;
  365. unsigned long start, stop;
  366. struct tpm_chip *chip = &g_chip;
  367. /* switch endianess: big->little */
  368. count = get_unaligned_be32(buf + TPM_CMD_COUNT_BYTE);
  369. ordinal = get_unaligned_be32(buf + TPM_CMD_ORDINAL_BYTE);
  370. if (count == 0) {
  371. error("no data\n");
  372. return -ENODATA;
  373. }
  374. if (count > bufsiz) {
  375. error("invalid count value %x %zx\n", count, bufsiz);
  376. return -E2BIG;
  377. }
  378. debug("Calling send\n");
  379. rc = chip->vendor.send(chip, (u8 *)buf, count);
  380. debug(" ... done calling send\n");
  381. if (rc < 0) {
  382. error("tpm_transmit: tpm_send: error %d\n", rc);
  383. goto out;
  384. }
  385. if (chip->vendor.irq)
  386. goto out_recv;
  387. start = get_timer(0);
  388. stop = tpm_calc_ordinal_duration(chip, ordinal);
  389. do {
  390. debug("waiting for status... %ld %ld\n", start, stop);
  391. u8 status = chip->vendor.status(chip);
  392. if ((status & chip->vendor.req_complete_mask) ==
  393. chip->vendor.req_complete_val) {
  394. debug("...got it;\n");
  395. goto out_recv;
  396. }
  397. if (status == chip->vendor.req_canceled) {
  398. error("Operation Canceled\n");
  399. rc = -ECANCELED;
  400. goto out;
  401. }
  402. udelay(TPM_TIMEOUT * 1000);
  403. } while (get_timer(start) < stop);
  404. chip->vendor.cancel(chip);
  405. error("Operation Timed out\n");
  406. rc = -ETIME;
  407. goto out;
  408. out_recv:
  409. debug("out_recv: reading response...\n");
  410. rc = chip->vendor.recv(chip, (u8 *)buf, TPM_BUFSIZE);
  411. if (rc < 0)
  412. error("tpm_transmit: tpm_recv: error %d\n", rc);
  413. out:
  414. return rc;
  415. }
  416. #ifdef CONFIG_DM_I2C
  417. static int tpm_open_dev(struct udevice *dev)
  418. {
  419. int rc;
  420. debug("%s: start\n", __func__);
  421. if (g_chip.is_open)
  422. return -EBUSY;
  423. rc = tpm_vendor_init_dev(dev);
  424. if (rc < 0)
  425. g_chip.is_open = 0;
  426. return rc;
  427. }
  428. #else
  429. static int tpm_open(uint32_t dev_addr)
  430. {
  431. int rc;
  432. if (g_chip.is_open)
  433. return -EBUSY;
  434. rc = tpm_vendor_init(dev_addr);
  435. if (rc < 0)
  436. g_chip.is_open = 0;
  437. return rc;
  438. }
  439. #endif
  440. static void tpm_close(void)
  441. {
  442. if (g_chip.is_open) {
  443. tpm_vendor_cleanup(&g_chip);
  444. g_chip.is_open = 0;
  445. }
  446. }
  447. static int tpm_select(void)
  448. {
  449. #ifndef CONFIG_DM_I2C
  450. int ret;
  451. tpm.old_bus = i2c_get_bus_num();
  452. if (tpm.old_bus != tpm.i2c_bus) {
  453. ret = i2c_set_bus_num(tpm.i2c_bus);
  454. if (ret) {
  455. debug("%s: Fail to set i2c bus %d\n", __func__,
  456. tpm.i2c_bus);
  457. return -1;
  458. }
  459. }
  460. #endif
  461. return 0;
  462. }
  463. static int tpm_deselect(void)
  464. {
  465. #ifndef CONFIG_DM_I2C
  466. int ret;
  467. if (tpm.old_bus != i2c_get_bus_num()) {
  468. ret = i2c_set_bus_num(tpm.old_bus);
  469. if (ret) {
  470. debug("%s: Fail to restore i2c bus %d\n",
  471. __func__, tpm.old_bus);
  472. return -1;
  473. }
  474. }
  475. tpm.old_bus = -1;
  476. #endif
  477. return 0;
  478. }
  479. /**
  480. * Decode TPM configuration.
  481. *
  482. * @param dev Returns a configuration of TPM device
  483. * @return 0 if ok, -1 on error
  484. */
  485. static int tpm_decode_config(struct tpm *dev)
  486. {
  487. const void *blob = gd->fdt_blob;
  488. int parent;
  489. int node;
  490. node = fdtdec_next_compatible(blob, 0, COMPAT_INFINEON_SLB9635_TPM);
  491. if (node < 0) {
  492. node = fdtdec_next_compatible(blob, 0,
  493. COMPAT_INFINEON_SLB9645_TPM);
  494. }
  495. if (node < 0) {
  496. debug("%s: Node not found\n", __func__);
  497. return -1;
  498. }
  499. parent = fdt_parent_offset(blob, node);
  500. if (parent < 0) {
  501. debug("%s: Cannot find node parent\n", __func__);
  502. return -1;
  503. }
  504. #ifdef CONFIG_DM_I2C
  505. struct udevice *bus;
  506. int chip_addr;
  507. int ret;
  508. /*
  509. * TODO(sjg@chromium.org): Remove this when driver model supports
  510. * TPMs
  511. */
  512. ret = uclass_get_device_by_of_offset(UCLASS_I2C, parent, &bus);
  513. if (ret) {
  514. debug("Cannot find bus for node '%s: ret=%d'\n",
  515. fdt_get_name(blob, parent, NULL), ret);
  516. return ret;
  517. }
  518. chip_addr = fdtdec_get_int(blob, node, "reg", -1);
  519. if (chip_addr == -1) {
  520. debug("Cannot find reg property for node '%s: ret=%d'\n",
  521. fdt_get_name(blob, node, NULL), ret);
  522. return ret;
  523. }
  524. /*
  525. * TODO(sjg@chromium.org): Older TPMs will need to use the older method
  526. * in iic_tpm_read() so the offset length needs to be 0 here.
  527. */
  528. ret = i2c_get_chip(bus, chip_addr, 1, &dev->dev);
  529. if (ret) {
  530. debug("Cannot find device for node '%s: ret=%d'\n",
  531. fdt_get_name(blob, node, NULL), ret);
  532. return ret;
  533. }
  534. #else
  535. int i2c_bus;
  536. i2c_bus = i2c_get_bus_num_fdt(parent);
  537. if (i2c_bus < 0)
  538. return -1;
  539. dev->i2c_bus = i2c_bus;
  540. dev->slave_addr = fdtdec_get_addr(blob, node, "reg");
  541. #endif
  542. return 0;
  543. }
  544. struct tpm_chip *tpm_register_hardware(const struct tpm_vendor_specific *entry)
  545. {
  546. struct tpm_chip *chip;
  547. /* Driver specific per-device data */
  548. chip = &g_chip;
  549. memcpy(&chip->vendor, entry, sizeof(struct tpm_vendor_specific));
  550. chip->is_open = 1;
  551. return chip;
  552. }
  553. int tis_init(void)
  554. {
  555. if (tpm.inited)
  556. return 0;
  557. if (tpm_decode_config(&tpm))
  558. return -1;
  559. if (tpm_select())
  560. return -1;
  561. #ifndef CONFIG_DM_I2C
  562. /*
  563. * Probe TPM twice; the first probing might fail because TPM is asleep,
  564. * and the probing can wake up TPM.
  565. */
  566. if (i2c_probe(tpm.slave_addr) && i2c_probe(tpm.slave_addr)) {
  567. debug("%s: fail to probe i2c addr 0x%x\n", __func__,
  568. tpm.slave_addr);
  569. return -1;
  570. }
  571. #endif
  572. tpm_deselect();
  573. debug("%s: done\n", __func__);
  574. tpm.inited = 1;
  575. return 0;
  576. }
  577. int tis_open(void)
  578. {
  579. int rc;
  580. if (!tpm.inited)
  581. return -1;
  582. if (tpm_select())
  583. return -1;
  584. #ifdef CONFIG_DM_I2C
  585. rc = tpm_open_dev(tpm.dev);
  586. #else
  587. rc = tpm_open(tpm.slave_addr);
  588. #endif
  589. tpm_deselect();
  590. return rc;
  591. }
  592. int tis_close(void)
  593. {
  594. if (!tpm.inited)
  595. return -1;
  596. if (tpm_select())
  597. return -1;
  598. tpm_close();
  599. tpm_deselect();
  600. return 0;
  601. }
  602. int tis_sendrecv(const uint8_t *sendbuf, size_t sbuf_size,
  603. uint8_t *recvbuf, size_t *rbuf_len)
  604. {
  605. int len;
  606. uint8_t buf[4096];
  607. if (!tpm.inited)
  608. return -1;
  609. if (sizeof(buf) < sbuf_size)
  610. return -1;
  611. memcpy(buf, sendbuf, sbuf_size);
  612. if (tpm_select())
  613. return -1;
  614. len = tpm_transmit(buf, sbuf_size);
  615. tpm_deselect();
  616. if (len < 10) {
  617. *rbuf_len = 0;
  618. return -1;
  619. }
  620. memcpy(recvbuf, buf, len);
  621. *rbuf_len = len;
  622. return 0;
  623. }