tpm_tis_common.c 26 KB

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