tpm_tis_common.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892
  1. /*
  2. * tpm_tis_common.c - QEMU's TPM TIS interface emulator
  3. * device agnostic functions
  4. *
  5. * Copyright (C) 2006,2010-2013 IBM Corporation
  6. *
  7. * Authors:
  8. * Stefan Berger <stefanb@us.ibm.com>
  9. * David Safford <safford@us.ibm.com>
  10. *
  11. * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
  12. *
  13. * This work is licensed under the terms of the GNU GPL, version 2 or later.
  14. * See the COPYING file in the top-level directory.
  15. *
  16. * Implementation of the TIS interface according to specs found at
  17. * http://www.trustedcomputinggroup.org. This implementation currently
  18. * supports version 1.3, 21 March 2013
  19. * In the developers menu choose the PC Client section then find the TIS
  20. * specification.
  21. *
  22. * TPM TIS for TPM 2 implementation following TCG PC Client Platform
  23. * TPM Profile (PTP) Specification, Family 2.0, Revision 00.43
  24. */
  25. #include "qemu/osdep.h"
  26. #include "hw/irq.h"
  27. #include "hw/isa/isa.h"
  28. #include "qapi/error.h"
  29. #include "qemu/bswap.h"
  30. #include "qemu/crc-ccitt.h"
  31. #include "qemu/module.h"
  32. #include "hw/acpi/tpm.h"
  33. #include "hw/pci/pci_ids.h"
  34. #include "hw/qdev-properties.h"
  35. #include "migration/vmstate.h"
  36. #include "system/tpm_backend.h"
  37. #include "system/tpm_util.h"
  38. #include "tpm_ppi.h"
  39. #include "trace.h"
  40. #include "tpm_tis.h"
  41. #define DEBUG_TIS 0
  42. /* local prototypes */
  43. static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
  44. unsigned size);
  45. /* utility functions */
  46. static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
  47. {
  48. uint8_t locty;
  49. locty = (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
  50. assert(TPM_TIS_IS_VALID_LOCTY(locty));
  51. return locty;
  52. }
  53. /*
  54. * Set the given flags in the STS register by clearing the register but
  55. * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting
  56. * the new flags.
  57. *
  58. * The SELFTEST_DONE flag is acquired from the backend that determines it by
  59. * peeking into TPM commands.
  60. *
  61. * A VM suspend/resume will preserve the flag by storing it into the VM
  62. * device state, but the backend will not remember it when QEMU is started
  63. * again. Therefore, we cache the flag here. Once set, it will not be unset
  64. * except by a reset.
  65. */
  66. static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
  67. {
  68. l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK;
  69. l->sts |= flags;
  70. }
  71. /*
  72. * Send a request to the TPM.
  73. */
  74. static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
  75. {
  76. tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM");
  77. /*
  78. * rw_offset serves as length indicator for length of data;
  79. * it's reset when the response comes back
  80. */
  81. s->loc[locty].state = TPM_TIS_STATE_EXECUTION;
  82. s->cmd = (TPMBackendCmd) {
  83. .locty = locty,
  84. .in = s->buffer,
  85. .in_len = s->rw_offset,
  86. .out = s->buffer,
  87. .out_len = s->be_buffer_size,
  88. };
  89. tpm_backend_deliver_request(s->be_driver, &s->cmd);
  90. }
  91. /* raise an interrupt if allowed */
  92. static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
  93. {
  94. if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
  95. return;
  96. }
  97. if ((s->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
  98. (s->loc[locty].inte & irqmask)) {
  99. trace_tpm_tis_raise_irq(irqmask);
  100. qemu_irq_raise(s->irq);
  101. s->loc[locty].ints |= irqmask;
  102. }
  103. }
  104. static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
  105. {
  106. uint8_t l;
  107. for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
  108. if (l == locty) {
  109. continue;
  110. }
  111. if ((s->loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
  112. return 1;
  113. }
  114. }
  115. return 0;
  116. }
  117. static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
  118. {
  119. bool change = (s->active_locty != new_active_locty);
  120. bool is_seize;
  121. uint8_t mask;
  122. if (change && TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
  123. is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
  124. s->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
  125. if (is_seize) {
  126. mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
  127. } else {
  128. mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
  129. TPM_TIS_ACCESS_REQUEST_USE);
  130. }
  131. /* reset flags on the old active locality */
  132. s->loc[s->active_locty].access &= mask;
  133. if (is_seize) {
  134. s->loc[s->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
  135. }
  136. }
  137. s->active_locty = new_active_locty;
  138. trace_tpm_tis_new_active_locality(s->active_locty);
  139. if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
  140. /* set flags on the new active locality */
  141. s->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
  142. s->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
  143. TPM_TIS_ACCESS_SEIZE);
  144. }
  145. if (change) {
  146. tpm_tis_raise_irq(s, s->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
  147. }
  148. }
  149. /* abort -- this function switches the locality */
  150. static void tpm_tis_abort(TPMState *s)
  151. {
  152. s->rw_offset = 0;
  153. trace_tpm_tis_abort(s->next_locty);
  154. /*
  155. * Need to react differently depending on who's aborting now and
  156. * which locality will become active afterwards.
  157. */
  158. if (s->aborting_locty == s->next_locty) {
  159. s->loc[s->aborting_locty].state = TPM_TIS_STATE_READY;
  160. tpm_tis_sts_set(&s->loc[s->aborting_locty],
  161. TPM_TIS_STS_COMMAND_READY);
  162. tpm_tis_raise_irq(s, s->aborting_locty, TPM_TIS_INT_COMMAND_READY);
  163. }
  164. /* locality after abort is another one than the current one */
  165. tpm_tis_new_active_locality(s, s->next_locty);
  166. s->next_locty = TPM_TIS_NO_LOCALITY;
  167. /* nobody's aborting a command anymore */
  168. s->aborting_locty = TPM_TIS_NO_LOCALITY;
  169. }
  170. /* prepare aborting current command */
  171. static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
  172. {
  173. uint8_t busy_locty;
  174. assert(TPM_TIS_IS_VALID_LOCTY(newlocty));
  175. s->aborting_locty = locty; /* may also be TPM_TIS_NO_LOCALITY */
  176. s->next_locty = newlocty; /* locality after successful abort */
  177. /*
  178. * only abort a command using an interrupt if currently executing
  179. * a command AND if there's a valid connection to the vTPM.
  180. */
  181. for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
  182. if (s->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
  183. /*
  184. * request the backend to cancel. Some backends may not
  185. * support it
  186. */
  187. tpm_backend_cancel_cmd(s->be_driver);
  188. return;
  189. }
  190. }
  191. tpm_tis_abort(s);
  192. }
  193. /*
  194. * Callback from the TPM to indicate that the response was received.
  195. */
  196. void tpm_tis_request_completed(TPMState *s, int ret)
  197. {
  198. uint8_t locty = s->cmd.locty;
  199. uint8_t l;
  200. assert(TPM_TIS_IS_VALID_LOCTY(locty));
  201. if (s->cmd.selftest_done) {
  202. for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
  203. s->loc[l].sts |= TPM_TIS_STS_SELFTEST_DONE;
  204. }
  205. }
  206. /* FIXME: report error if ret != 0 */
  207. tpm_tis_sts_set(&s->loc[locty],
  208. TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
  209. s->loc[locty].state = TPM_TIS_STATE_COMPLETION;
  210. s->rw_offset = 0;
  211. tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM");
  212. if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) {
  213. tpm_tis_abort(s);
  214. }
  215. tpm_tis_raise_irq(s, locty,
  216. TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
  217. }
  218. /*
  219. * Read a byte of response data
  220. */
  221. static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
  222. {
  223. uint32_t ret = TPM_TIS_NO_DATA_BYTE;
  224. uint16_t len;
  225. if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
  226. len = MIN(tpm_cmd_get_size(&s->buffer),
  227. s->be_buffer_size);
  228. ret = s->buffer[s->rw_offset++];
  229. if (s->rw_offset >= len) {
  230. /* got last byte */
  231. tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
  232. tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
  233. }
  234. trace_tpm_tis_data_read(ret, s->rw_offset - 1);
  235. }
  236. return ret;
  237. }
  238. #ifdef DEBUG_TIS
  239. static void tpm_tis_dump_state(TPMState *s, hwaddr addr)
  240. {
  241. static const unsigned regs[] = {
  242. TPM_TIS_REG_ACCESS,
  243. TPM_TIS_REG_INT_ENABLE,
  244. TPM_TIS_REG_INT_VECTOR,
  245. TPM_TIS_REG_INT_STATUS,
  246. TPM_TIS_REG_INTF_CAPABILITY,
  247. TPM_TIS_REG_STS,
  248. TPM_TIS_REG_DID_VID,
  249. TPM_TIS_REG_RID,
  250. 0xfff};
  251. int idx;
  252. uint8_t locty = tpm_tis_locality_from_addr(addr);
  253. hwaddr base = addr & ~0xfff;
  254. printf("tpm_tis: active locality : %d\n"
  255. "tpm_tis: state of locality %d : %d\n"
  256. "tpm_tis: register dump:\n",
  257. s->active_locty,
  258. locty, s->loc[locty].state);
  259. for (idx = 0; regs[idx] != 0xfff; idx++) {
  260. printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
  261. (int)tpm_tis_mmio_read(s, base + regs[idx], 4));
  262. }
  263. printf("tpm_tis: r/w offset : %d\n"
  264. "tpm_tis: result buffer : ",
  265. s->rw_offset);
  266. for (idx = 0;
  267. idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size);
  268. idx++) {
  269. printf("%c%02x%s",
  270. s->rw_offset == idx ? '>' : ' ',
  271. s->buffer[idx],
  272. ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
  273. }
  274. printf("\n");
  275. }
  276. #endif
  277. /*
  278. * Read a register of the TIS interface
  279. * See specs pages 33-63 for description of the registers
  280. */
  281. static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
  282. unsigned size)
  283. {
  284. TPMState *s = opaque;
  285. uint16_t offset = addr & 0xffc;
  286. uint8_t shift = (addr & 0x3) * 8;
  287. uint32_t val = 0xffffffff;
  288. uint8_t locty = tpm_tis_locality_from_addr(addr);
  289. uint32_t avail;
  290. uint8_t v;
  291. if (tpm_backend_had_startup_error(s->be_driver)) {
  292. return 0;
  293. }
  294. switch (offset) {
  295. case TPM_TIS_REG_ACCESS:
  296. /* never show the SEIZE flag even though we use it internally */
  297. val = s->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
  298. /* the pending flag is always calculated */
  299. if (tpm_tis_check_request_use_except(s, locty)) {
  300. val |= TPM_TIS_ACCESS_PENDING_REQUEST;
  301. }
  302. val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
  303. break;
  304. case TPM_TIS_REG_INT_ENABLE:
  305. val = s->loc[locty].inte;
  306. break;
  307. case TPM_TIS_REG_INT_VECTOR:
  308. val = s->irq_num;
  309. break;
  310. case TPM_TIS_REG_INT_STATUS:
  311. val = s->loc[locty].ints;
  312. break;
  313. case TPM_TIS_REG_INTF_CAPABILITY:
  314. switch (s->be_tpm_version) {
  315. case TPM_VERSION_UNSPEC:
  316. val = 0;
  317. break;
  318. case TPM_VERSION_1_2:
  319. val = TPM_TIS_CAPABILITIES_SUPPORTED1_3;
  320. break;
  321. case TPM_VERSION_2_0:
  322. val = TPM_TIS_CAPABILITIES_SUPPORTED2_0;
  323. break;
  324. }
  325. break;
  326. case TPM_TIS_REG_STS:
  327. if (s->active_locty == locty) {
  328. if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
  329. val = TPM_TIS_BURST_COUNT(
  330. MIN(tpm_cmd_get_size(&s->buffer),
  331. s->be_buffer_size)
  332. - s->rw_offset) | s->loc[locty].sts;
  333. } else {
  334. avail = s->be_buffer_size - s->rw_offset;
  335. /*
  336. * byte-sized reads should not return 0x00 for 0x100
  337. * available bytes.
  338. */
  339. if (size == 1 && avail > 0xff) {
  340. avail = 0xff;
  341. }
  342. val = TPM_TIS_BURST_COUNT(avail) | s->loc[locty].sts;
  343. }
  344. }
  345. break;
  346. case TPM_TIS_REG_DATA_FIFO:
  347. case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
  348. if (s->active_locty == locty) {
  349. if (size > 4 - (addr & 0x3)) {
  350. /* prevent access beyond FIFO */
  351. size = 4 - (addr & 0x3);
  352. }
  353. val = 0;
  354. shift = 0;
  355. while (size > 0) {
  356. switch (s->loc[locty].state) {
  357. case TPM_TIS_STATE_COMPLETION:
  358. v = tpm_tis_data_read(s, locty);
  359. break;
  360. default:
  361. v = TPM_TIS_NO_DATA_BYTE;
  362. break;
  363. }
  364. val |= (v << shift);
  365. shift += 8;
  366. size--;
  367. }
  368. shift = 0; /* no more adjustments */
  369. }
  370. break;
  371. case TPM_TIS_REG_INTERFACE_ID:
  372. val = s->loc[locty].iface_id;
  373. break;
  374. case TPM_TIS_REG_DID_VID:
  375. val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
  376. break;
  377. case TPM_TIS_REG_RID:
  378. val = TPM_TIS_TPM_RID;
  379. break;
  380. #ifdef DEBUG_TIS
  381. case TPM_TIS_REG_DEBUG:
  382. tpm_tis_dump_state(s, addr);
  383. break;
  384. #endif
  385. }
  386. if (shift) {
  387. val >>= shift;
  388. }
  389. trace_tpm_tis_mmio_read(size, addr, val);
  390. return val;
  391. }
  392. /*
  393. * A wrapper read function so that it can be directly called without
  394. * mmio.
  395. */
  396. uint32_t tpm_tis_read_data(TPMState *s, hwaddr addr, unsigned size)
  397. {
  398. return tpm_tis_mmio_read(s, addr, size);
  399. }
  400. /*
  401. * Calculate current data buffer checksum
  402. */
  403. uint16_t tpm_tis_get_checksum(TPMState *s)
  404. {
  405. return bswap16(crc_ccitt(0, s->buffer, s->rw_offset));
  406. }
  407. /*
  408. * Write a value to a register of the TIS interface
  409. * See specs pages 33-63 for description of the registers
  410. */
  411. static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
  412. uint64_t val, unsigned size)
  413. {
  414. TPMState *s = opaque;
  415. uint16_t off = addr & 0xffc;
  416. uint8_t shift = (addr & 0x3) * 8;
  417. uint8_t locty = tpm_tis_locality_from_addr(addr);
  418. uint8_t active_locty, l;
  419. int c, set_new_locty = 1;
  420. uint16_t len;
  421. uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);
  422. trace_tpm_tis_mmio_write(size, addr, val);
  423. if (locty == 4) {
  424. trace_tpm_tis_mmio_write_locty4();
  425. return;
  426. }
  427. if (tpm_backend_had_startup_error(s->be_driver)) {
  428. return;
  429. }
  430. val &= mask;
  431. if (shift) {
  432. val <<= shift;
  433. mask <<= shift;
  434. }
  435. mask ^= 0xffffffff;
  436. switch (off) {
  437. case TPM_TIS_REG_ACCESS:
  438. if ((val & TPM_TIS_ACCESS_SEIZE)) {
  439. val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
  440. TPM_TIS_ACCESS_ACTIVE_LOCALITY);
  441. }
  442. active_locty = s->active_locty;
  443. if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
  444. /* give up locality if currently owned */
  445. if (s->active_locty == locty) {
  446. trace_tpm_tis_mmio_write_release_locty(locty);
  447. uint8_t newlocty = TPM_TIS_NO_LOCALITY;
  448. /* anybody wants the locality ? */
  449. for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
  450. if ((s->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
  451. trace_tpm_tis_mmio_write_locty_req_use(c);
  452. newlocty = c;
  453. break;
  454. }
  455. }
  456. trace_tpm_tis_mmio_write_next_locty(newlocty);
  457. if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
  458. set_new_locty = 0;
  459. tpm_tis_prep_abort(s, locty, newlocty);
  460. } else {
  461. active_locty = TPM_TIS_NO_LOCALITY;
  462. }
  463. } else {
  464. /* not currently the owner; clear a pending request */
  465. s->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
  466. }
  467. }
  468. if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
  469. s->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
  470. }
  471. if ((val & TPM_TIS_ACCESS_SEIZE)) {
  472. /*
  473. * allow seize if a locality is active and the requesting
  474. * locality is higher than the one that's active
  475. * OR
  476. * allow seize for requesting locality if no locality is
  477. * active
  478. */
  479. while ((TPM_TIS_IS_VALID_LOCTY(s->active_locty) &&
  480. locty > s->active_locty) ||
  481. !TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
  482. bool higher_seize = false;
  483. /* already a pending SEIZE ? */
  484. if ((s->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
  485. break;
  486. }
  487. /* check for ongoing seize by a higher locality */
  488. for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
  489. if ((s->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
  490. higher_seize = true;
  491. break;
  492. }
  493. }
  494. if (higher_seize) {
  495. break;
  496. }
  497. /* cancel any seize by a lower locality */
  498. for (l = 0; l < locty; l++) {
  499. s->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
  500. }
  501. s->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
  502. trace_tpm_tis_mmio_write_locty_seized(locty, s->active_locty);
  503. trace_tpm_tis_mmio_write_init_abort();
  504. set_new_locty = 0;
  505. tpm_tis_prep_abort(s, s->active_locty, locty);
  506. break;
  507. }
  508. }
  509. if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
  510. if (s->active_locty != locty) {
  511. if (TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
  512. s->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
  513. } else {
  514. /* no locality active -> make this one active now */
  515. active_locty = locty;
  516. }
  517. }
  518. }
  519. if (set_new_locty) {
  520. tpm_tis_new_active_locality(s, active_locty);
  521. }
  522. break;
  523. case TPM_TIS_REG_INT_ENABLE:
  524. s->loc[locty].inte &= mask;
  525. s->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED |
  526. TPM_TIS_INT_POLARITY_MASK |
  527. TPM_TIS_INTERRUPTS_SUPPORTED));
  528. break;
  529. case TPM_TIS_REG_INT_VECTOR:
  530. /* hard wired -- ignore */
  531. break;
  532. case TPM_TIS_REG_INT_STATUS:
  533. /* clearing of interrupt flags */
  534. if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
  535. (s->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
  536. s->loc[locty].ints &= ~val;
  537. if (s->loc[locty].ints == 0) {
  538. qemu_irq_lower(s->irq);
  539. trace_tpm_tis_mmio_write_lowering_irq();
  540. }
  541. }
  542. s->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
  543. break;
  544. case TPM_TIS_REG_STS:
  545. if (s->active_locty != locty) {
  546. break;
  547. }
  548. if (s->be_tpm_version == TPM_VERSION_2_0) {
  549. /* some flags that are only supported for TPM 2 */
  550. if (val & TPM_TIS_STS_COMMAND_CANCEL) {
  551. if (s->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
  552. /*
  553. * request the backend to cancel. Some backends may not
  554. * support it
  555. */
  556. tpm_backend_cancel_cmd(s->be_driver);
  557. }
  558. }
  559. if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) {
  560. if (locty == 3 || locty == 4) {
  561. tpm_backend_reset_tpm_established_flag(s->be_driver, locty);
  562. }
  563. }
  564. }
  565. val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
  566. TPM_TIS_STS_RESPONSE_RETRY);
  567. if (val == TPM_TIS_STS_COMMAND_READY) {
  568. switch (s->loc[locty].state) {
  569. case TPM_TIS_STATE_READY:
  570. s->rw_offset = 0;
  571. break;
  572. case TPM_TIS_STATE_IDLE:
  573. tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_COMMAND_READY);
  574. s->loc[locty].state = TPM_TIS_STATE_READY;
  575. tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
  576. break;
  577. case TPM_TIS_STATE_EXECUTION:
  578. case TPM_TIS_STATE_RECEPTION:
  579. /* abort currently running command */
  580. trace_tpm_tis_mmio_write_init_abort();
  581. tpm_tis_prep_abort(s, locty, locty);
  582. break;
  583. case TPM_TIS_STATE_COMPLETION:
  584. s->rw_offset = 0;
  585. /* shortcut to ready state with C/R set */
  586. s->loc[locty].state = TPM_TIS_STATE_READY;
  587. if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
  588. tpm_tis_sts_set(&s->loc[locty],
  589. TPM_TIS_STS_COMMAND_READY);
  590. tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
  591. }
  592. s->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
  593. break;
  594. }
  595. } else if (val == TPM_TIS_STS_TPM_GO) {
  596. switch (s->loc[locty].state) {
  597. case TPM_TIS_STATE_RECEPTION:
  598. if ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
  599. tpm_tis_tpm_send(s, locty);
  600. }
  601. break;
  602. default:
  603. /* ignore */
  604. break;
  605. }
  606. } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
  607. switch (s->loc[locty].state) {
  608. case TPM_TIS_STATE_COMPLETION:
  609. s->rw_offset = 0;
  610. tpm_tis_sts_set(&s->loc[locty],
  611. TPM_TIS_STS_VALID|
  612. TPM_TIS_STS_DATA_AVAILABLE);
  613. break;
  614. default:
  615. /* ignore */
  616. break;
  617. }
  618. }
  619. break;
  620. case TPM_TIS_REG_DATA_FIFO:
  621. case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
  622. /* data fifo */
  623. if (s->active_locty != locty) {
  624. break;
  625. }
  626. if (s->loc[locty].state == TPM_TIS_STATE_IDLE ||
  627. s->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
  628. s->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
  629. /* drop the byte */
  630. } else {
  631. trace_tpm_tis_mmio_write_data2send(val, size);
  632. if (s->loc[locty].state == TPM_TIS_STATE_READY) {
  633. s->loc[locty].state = TPM_TIS_STATE_RECEPTION;
  634. tpm_tis_sts_set(&s->loc[locty],
  635. TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
  636. }
  637. val >>= shift;
  638. if (size > 4 - (addr & 0x3)) {
  639. /* prevent access beyond FIFO */
  640. size = 4 - (addr & 0x3);
  641. }
  642. while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {
  643. if (s->rw_offset < s->be_buffer_size) {
  644. s->buffer[s->rw_offset++] =
  645. (uint8_t)val;
  646. val >>= 8;
  647. size--;
  648. } else {
  649. tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
  650. }
  651. }
  652. /* check for complete packet */
  653. if (s->rw_offset > 5 &&
  654. (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
  655. /* we have a packet length - see if we have all of it */
  656. bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID);
  657. len = tpm_cmd_get_size(&s->buffer);
  658. if (len > s->rw_offset) {
  659. tpm_tis_sts_set(&s->loc[locty],
  660. TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
  661. } else {
  662. /* packet complete */
  663. tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
  664. }
  665. if (need_irq) {
  666. tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
  667. }
  668. }
  669. }
  670. break;
  671. case TPM_TIS_REG_INTERFACE_ID:
  672. if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) {
  673. for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
  674. s->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK;
  675. }
  676. }
  677. break;
  678. }
  679. }
  680. /*
  681. * A wrapper write function so that it can be directly called without
  682. * mmio.
  683. */
  684. void tpm_tis_write_data(TPMState *s, hwaddr addr, uint64_t val, uint32_t size)
  685. {
  686. tpm_tis_mmio_write(s, addr, val, size);
  687. }
  688. const MemoryRegionOps tpm_tis_memory_ops = {
  689. .read = tpm_tis_mmio_read,
  690. .write = tpm_tis_mmio_write,
  691. .endianness = DEVICE_LITTLE_ENDIAN,
  692. .valid = {
  693. .min_access_size = 1,
  694. .max_access_size = 4,
  695. },
  696. };
  697. /*
  698. * Get the TPMVersion of the backend device being used
  699. */
  700. enum TPMVersion tpm_tis_get_tpm_version(TPMState *s)
  701. {
  702. if (tpm_backend_had_startup_error(s->be_driver)) {
  703. return TPM_VERSION_UNSPEC;
  704. }
  705. return tpm_backend_get_tpm_version(s->be_driver);
  706. }
  707. /*
  708. * This function is called when the machine starts, resets or due to
  709. * S3 resume.
  710. */
  711. void tpm_tis_reset(TPMState *s)
  712. {
  713. int c;
  714. s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
  715. s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
  716. TPM_TIS_BUFFER_MAX);
  717. if (s->ppi_enabled) {
  718. tpm_ppi_reset(&s->ppi);
  719. }
  720. tpm_backend_reset(s->be_driver);
  721. s->active_locty = TPM_TIS_NO_LOCALITY;
  722. s->next_locty = TPM_TIS_NO_LOCALITY;
  723. s->aborting_locty = TPM_TIS_NO_LOCALITY;
  724. for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
  725. s->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
  726. switch (s->be_tpm_version) {
  727. case TPM_VERSION_UNSPEC:
  728. break;
  729. case TPM_VERSION_1_2:
  730. s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2;
  731. s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3;
  732. break;
  733. case TPM_VERSION_2_0:
  734. s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0;
  735. s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0;
  736. break;
  737. }
  738. s->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
  739. s->loc[c].ints = 0;
  740. s->loc[c].state = TPM_TIS_STATE_IDLE;
  741. s->rw_offset = 0;
  742. }
  743. if (tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size) < 0) {
  744. exit(1);
  745. }
  746. }
  747. /* persistent state handling */
  748. int tpm_tis_pre_save(TPMState *s)
  749. {
  750. uint8_t locty = s->active_locty;
  751. trace_tpm_tis_pre_save(locty, s->rw_offset);
  752. if (DEBUG_TIS) {
  753. tpm_tis_dump_state(s, 0);
  754. }
  755. /*
  756. * Synchronize with backend completion.
  757. */
  758. tpm_backend_finish_sync(s->be_driver);
  759. return 0;
  760. }
  761. const VMStateDescription vmstate_locty = {
  762. .name = "tpm-tis/locty",
  763. .version_id = 0,
  764. .fields = (const VMStateField[]) {
  765. VMSTATE_UINT32(state, TPMLocality),
  766. VMSTATE_UINT32(inte, TPMLocality),
  767. VMSTATE_UINT32(ints, TPMLocality),
  768. VMSTATE_UINT8(access, TPMLocality),
  769. VMSTATE_UINT32(sts, TPMLocality),
  770. VMSTATE_UINT32(iface_id, TPMLocality),
  771. VMSTATE_END_OF_LIST(),
  772. }
  773. };