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