]> git.proxmox.com Git - mirror_qemu.git/blob - hw/tpm/tpm_tis.c
04e4ad9212d67c0fa5381d6f948d653c79a3600f
[mirror_qemu.git] / hw / tpm / tpm_tis.c
1 /*
2 * tpm_tis.c - QEMU's TPM TIS interface emulator
3 *
4 * Copyright (C) 2006,2010-2013 IBM Corporation
5 *
6 * Authors:
7 * Stefan Berger <stefanb@us.ibm.com>
8 * David Safford <safford@us.ibm.com>
9 *
10 * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
11 *
12 * This work is licensed under the terms of the GNU GPL, version 2 or later.
13 * See the COPYING file in the top-level directory.
14 *
15 * Implementation of the TIS interface according to specs found at
16 * http://www.trustedcomputinggroup.org. This implementation currently
17 * supports version 1.3, 21 March 2013
18 * In the developers menu choose the PC Client section then find the TIS
19 * specification.
20 *
21 * TPM TIS for TPM 2 implementation following TCG PC Client Platform
22 * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
23 */
24
25 #include "qemu/osdep.h"
26 #include "hw/isa/isa.h"
27 #include "qapi/error.h"
28
29 #include "hw/acpi/tpm.h"
30 #include "hw/pci/pci_ids.h"
31 #include "sysemu/tpm_backend.h"
32 #include "tpm_int.h"
33 #include "tpm_util.h"
34 #include "trace.h"
35
36 #define TPM_TIS_NUM_LOCALITIES 5 /* per spec */
37 #define TPM_TIS_LOCALITY_SHIFT 12
38 #define TPM_TIS_NO_LOCALITY 0xff
39
40 #define TPM_TIS_IS_VALID_LOCTY(x) ((x) < TPM_TIS_NUM_LOCALITIES)
41
42 #define TPM_TIS_BUFFER_MAX 4096
43
44 typedef enum {
45 TPM_TIS_STATE_IDLE = 0,
46 TPM_TIS_STATE_READY,
47 TPM_TIS_STATE_COMPLETION,
48 TPM_TIS_STATE_EXECUTION,
49 TPM_TIS_STATE_RECEPTION,
50 } TPMTISState;
51
52 /* locality data -- all fields are persisted */
53 typedef struct TPMLocality {
54 TPMTISState state;
55 uint8_t access;
56 uint32_t sts;
57 uint32_t iface_id;
58 uint32_t inte;
59 uint32_t ints;
60 } TPMLocality;
61
62 typedef struct TPMState {
63 ISADevice busdev;
64 MemoryRegion mmio;
65
66 unsigned char buffer[TPM_TIS_BUFFER_MAX];
67 uint16_t rw_offset;
68
69 uint8_t active_locty;
70 uint8_t aborting_locty;
71 uint8_t next_locty;
72
73 TPMLocality loc[TPM_TIS_NUM_LOCALITIES];
74
75 qemu_irq irq;
76 uint32_t irq_num;
77
78 TPMBackendCmd cmd;
79
80 TPMBackend *be_driver;
81 TPMVersion be_tpm_version;
82
83 size_t be_buffer_size;
84 } TPMState;
85
86 #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
87
88 #define DEBUG_TIS 0
89
90 /* local prototypes */
91
92 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
93 unsigned size);
94
95 /* utility functions */
96
97 static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
98 {
99 return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
100 }
101
102 static void tpm_tis_show_buffer(const unsigned char *buffer,
103 size_t buffer_size, const char *string)
104 {
105 uint32_t len, i;
106
107 len = MIN(tpm_cmd_get_size(buffer), buffer_size);
108 printf("tpm_tis: %s length = %d\n", string, len);
109 for (i = 0; i < len; i++) {
110 if (i && !(i % 16)) {
111 printf("\n");
112 }
113 printf("%.2X ", buffer[i]);
114 }
115 printf("\n");
116 }
117
118 /*
119 * Set the given flags in the STS register by clearing the register but
120 * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting
121 * the new flags.
122 *
123 * The SELFTEST_DONE flag is acquired from the backend that determines it by
124 * peeking into TPM commands.
125 *
126 * A VM suspend/resume will preserve the flag by storing it into the VM
127 * device state, but the backend will not remember it when QEMU is started
128 * again. Therefore, we cache the flag here. Once set, it will not be unset
129 * except by a reset.
130 */
131 static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
132 {
133 l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK;
134 l->sts |= flags;
135 }
136
137 /*
138 * Send a request to the TPM.
139 */
140 static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
141 {
142 if (DEBUG_TIS) {
143 tpm_tis_show_buffer(s->buffer, s->be_buffer_size,
144 "tpm_tis: To TPM");
145 }
146
147 /*
148 * rw_offset serves as length indicator for length of data;
149 * it's reset when the response comes back
150 */
151 s->loc[locty].state = TPM_TIS_STATE_EXECUTION;
152
153 s->cmd = (TPMBackendCmd) {
154 .locty = locty,
155 .in = s->buffer,
156 .in_len = s->rw_offset,
157 .out = s->buffer,
158 .out_len = s->be_buffer_size,
159 };
160
161 tpm_backend_deliver_request(s->be_driver, &s->cmd);
162 }
163
164 /* raise an interrupt if allowed */
165 static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
166 {
167 if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
168 return;
169 }
170
171 if ((s->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
172 (s->loc[locty].inte & irqmask)) {
173 trace_tpm_tis_raise_irq(irqmask);
174 qemu_irq_raise(s->irq);
175 s->loc[locty].ints |= irqmask;
176 }
177 }
178
179 static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
180 {
181 uint8_t l;
182
183 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
184 if (l == locty) {
185 continue;
186 }
187 if ((s->loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
188 return 1;
189 }
190 }
191
192 return 0;
193 }
194
195 static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
196 {
197 bool change = (s->active_locty != new_active_locty);
198 bool is_seize;
199 uint8_t mask;
200
201 if (change && TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
202 is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
203 s->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
204
205 if (is_seize) {
206 mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
207 } else {
208 mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
209 TPM_TIS_ACCESS_REQUEST_USE);
210 }
211 /* reset flags on the old active locality */
212 s->loc[s->active_locty].access &= mask;
213
214 if (is_seize) {
215 s->loc[s->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
216 }
217 }
218
219 s->active_locty = new_active_locty;
220
221 trace_tpm_tis_new_active_locality(s->active_locty);
222
223 if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
224 /* set flags on the new active locality */
225 s->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
226 s->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
227 TPM_TIS_ACCESS_SEIZE);
228 }
229
230 if (change) {
231 tpm_tis_raise_irq(s, s->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
232 }
233 }
234
235 /* abort -- this function switches the locality */
236 static void tpm_tis_abort(TPMState *s)
237 {
238 s->rw_offset = 0;
239
240 trace_tpm_tis_abort(s->next_locty);
241
242 /*
243 * Need to react differently depending on who's aborting now and
244 * which locality will become active afterwards.
245 */
246 if (s->aborting_locty == s->next_locty) {
247 s->loc[s->aborting_locty].state = TPM_TIS_STATE_READY;
248 tpm_tis_sts_set(&s->loc[s->aborting_locty],
249 TPM_TIS_STS_COMMAND_READY);
250 tpm_tis_raise_irq(s, s->aborting_locty, TPM_TIS_INT_COMMAND_READY);
251 }
252
253 /* locality after abort is another one than the current one */
254 tpm_tis_new_active_locality(s, s->next_locty);
255
256 s->next_locty = TPM_TIS_NO_LOCALITY;
257 /* nobody's aborting a command anymore */
258 s->aborting_locty = TPM_TIS_NO_LOCALITY;
259 }
260
261 /* prepare aborting current command */
262 static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
263 {
264 uint8_t busy_locty;
265
266 assert(TPM_TIS_IS_VALID_LOCTY(newlocty));
267
268 s->aborting_locty = locty; /* may also be TPM_TIS_NO_LOCALITY */
269 s->next_locty = newlocty; /* locality after successful abort */
270
271 /*
272 * only abort a command using an interrupt if currently executing
273 * a command AND if there's a valid connection to the vTPM.
274 */
275 for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
276 if (s->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
277 /*
278 * request the backend to cancel. Some backends may not
279 * support it
280 */
281 tpm_backend_cancel_cmd(s->be_driver);
282 return;
283 }
284 }
285
286 tpm_tis_abort(s);
287 }
288
289 /*
290 * Callback from the TPM to indicate that the response was received.
291 */
292 static void tpm_tis_request_completed(TPMIf *ti, int ret)
293 {
294 TPMState *s = TPM(ti);
295 uint8_t locty = s->cmd.locty;
296 uint8_t l;
297
298 if (s->cmd.selftest_done) {
299 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
300 s->loc[l].sts |= TPM_TIS_STS_SELFTEST_DONE;
301 }
302 }
303
304 /* FIXME: report error if ret != 0 */
305 tpm_tis_sts_set(&s->loc[locty],
306 TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
307 s->loc[locty].state = TPM_TIS_STATE_COMPLETION;
308 s->rw_offset = 0;
309
310 if (DEBUG_TIS) {
311 tpm_tis_show_buffer(s->buffer, s->be_buffer_size,
312 "tpm_tis: From TPM");
313 }
314
315 if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) {
316 tpm_tis_abort(s);
317 }
318
319 tpm_tis_raise_irq(s, locty,
320 TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
321 }
322
323 /*
324 * Read a byte of response data
325 */
326 static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
327 {
328 uint32_t ret = TPM_TIS_NO_DATA_BYTE;
329 uint16_t len;
330
331 if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
332 len = MIN(tpm_cmd_get_size(&s->buffer),
333 s->be_buffer_size);
334
335 ret = s->buffer[s->rw_offset++];
336 if (s->rw_offset >= len) {
337 /* got last byte */
338 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
339 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
340 }
341 trace_tpm_tis_data_read(ret, s->rw_offset - 1);
342 }
343
344 return ret;
345 }
346
347 #ifdef DEBUG_TIS
348 static void tpm_tis_dump_state(void *opaque, hwaddr addr)
349 {
350 static const unsigned regs[] = {
351 TPM_TIS_REG_ACCESS,
352 TPM_TIS_REG_INT_ENABLE,
353 TPM_TIS_REG_INT_VECTOR,
354 TPM_TIS_REG_INT_STATUS,
355 TPM_TIS_REG_INTF_CAPABILITY,
356 TPM_TIS_REG_STS,
357 TPM_TIS_REG_DID_VID,
358 TPM_TIS_REG_RID,
359 0xfff};
360 int idx;
361 uint8_t locty = tpm_tis_locality_from_addr(addr);
362 hwaddr base = addr & ~0xfff;
363 TPMState *s = opaque;
364
365 printf("tpm_tis: active locality : %d\n"
366 "tpm_tis: state of locality %d : %d\n"
367 "tpm_tis: register dump:\n",
368 s->active_locty,
369 locty, s->loc[locty].state);
370
371 for (idx = 0; regs[idx] != 0xfff; idx++) {
372 printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
373 (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
374 }
375
376 printf("tpm_tis: r/w offset : %d\n"
377 "tpm_tis: result buffer : ",
378 s->rw_offset);
379 for (idx = 0;
380 idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size);
381 idx++) {
382 printf("%c%02x%s",
383 s->rw_offset == idx ? '>' : ' ',
384 s->buffer[idx],
385 ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
386 }
387 printf("\n");
388 }
389 #endif
390
391 /*
392 * Read a register of the TIS interface
393 * See specs pages 33-63 for description of the registers
394 */
395 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
396 unsigned size)
397 {
398 TPMState *s = opaque;
399 uint16_t offset = addr & 0xffc;
400 uint8_t shift = (addr & 0x3) * 8;
401 uint32_t val = 0xffffffff;
402 uint8_t locty = tpm_tis_locality_from_addr(addr);
403 uint32_t avail;
404 uint8_t v;
405
406 if (tpm_backend_had_startup_error(s->be_driver)) {
407 return 0;
408 }
409
410 switch (offset) {
411 case TPM_TIS_REG_ACCESS:
412 /* never show the SEIZE flag even though we use it internally */
413 val = s->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
414 /* the pending flag is always calculated */
415 if (tpm_tis_check_request_use_except(s, locty)) {
416 val |= TPM_TIS_ACCESS_PENDING_REQUEST;
417 }
418 val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
419 break;
420 case TPM_TIS_REG_INT_ENABLE:
421 val = s->loc[locty].inte;
422 break;
423 case TPM_TIS_REG_INT_VECTOR:
424 val = s->irq_num;
425 break;
426 case TPM_TIS_REG_INT_STATUS:
427 val = s->loc[locty].ints;
428 break;
429 case TPM_TIS_REG_INTF_CAPABILITY:
430 switch (s->be_tpm_version) {
431 case TPM_VERSION_UNSPEC:
432 val = 0;
433 break;
434 case TPM_VERSION_1_2:
435 val = TPM_TIS_CAPABILITIES_SUPPORTED1_3;
436 break;
437 case TPM_VERSION_2_0:
438 val = TPM_TIS_CAPABILITIES_SUPPORTED2_0;
439 break;
440 }
441 break;
442 case TPM_TIS_REG_STS:
443 if (s->active_locty == locty) {
444 if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
445 val = TPM_TIS_BURST_COUNT(
446 MIN(tpm_cmd_get_size(&s->buffer),
447 s->be_buffer_size)
448 - s->rw_offset) | s->loc[locty].sts;
449 } else {
450 avail = s->be_buffer_size - s->rw_offset;
451 /*
452 * byte-sized reads should not return 0x00 for 0x100
453 * available bytes.
454 */
455 if (size == 1 && avail > 0xff) {
456 avail = 0xff;
457 }
458 val = TPM_TIS_BURST_COUNT(avail) | s->loc[locty].sts;
459 }
460 }
461 break;
462 case TPM_TIS_REG_DATA_FIFO:
463 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
464 if (s->active_locty == locty) {
465 if (size > 4 - (addr & 0x3)) {
466 /* prevent access beyond FIFO */
467 size = 4 - (addr & 0x3);
468 }
469 val = 0;
470 shift = 0;
471 while (size > 0) {
472 switch (s->loc[locty].state) {
473 case TPM_TIS_STATE_COMPLETION:
474 v = tpm_tis_data_read(s, locty);
475 break;
476 default:
477 v = TPM_TIS_NO_DATA_BYTE;
478 break;
479 }
480 val |= (v << shift);
481 shift += 8;
482 size--;
483 }
484 shift = 0; /* no more adjustments */
485 }
486 break;
487 case TPM_TIS_REG_INTERFACE_ID:
488 val = s->loc[locty].iface_id;
489 break;
490 case TPM_TIS_REG_DID_VID:
491 val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
492 break;
493 case TPM_TIS_REG_RID:
494 val = TPM_TIS_TPM_RID;
495 break;
496 #ifdef DEBUG_TIS
497 case TPM_TIS_REG_DEBUG:
498 tpm_tis_dump_state(opaque, addr);
499 break;
500 #endif
501 }
502
503 if (shift) {
504 val >>= shift;
505 }
506
507 trace_tpm_tis_mmio_read(size, addr, val);
508
509 return val;
510 }
511
512 /*
513 * Write a value to a register of the TIS interface
514 * See specs pages 33-63 for description of the registers
515 */
516 static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
517 uint64_t val, unsigned size)
518 {
519 TPMState *s = opaque;
520 uint16_t off = addr & 0xffc;
521 uint8_t shift = (addr & 0x3) * 8;
522 uint8_t locty = tpm_tis_locality_from_addr(addr);
523 uint8_t active_locty, l;
524 int c, set_new_locty = 1;
525 uint16_t len;
526 uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);
527
528 trace_tpm_tis_mmio_write(size, addr, val);
529
530 if (locty == 4) {
531 trace_tpm_tis_mmio_write_locty4();
532 return;
533 }
534
535 if (tpm_backend_had_startup_error(s->be_driver)) {
536 return;
537 }
538
539 val &= mask;
540
541 if (shift) {
542 val <<= shift;
543 mask <<= shift;
544 }
545
546 mask ^= 0xffffffff;
547
548 switch (off) {
549 case TPM_TIS_REG_ACCESS:
550
551 if ((val & TPM_TIS_ACCESS_SEIZE)) {
552 val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
553 TPM_TIS_ACCESS_ACTIVE_LOCALITY);
554 }
555
556 active_locty = s->active_locty;
557
558 if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
559 /* give up locality if currently owned */
560 if (s->active_locty == locty) {
561 trace_tpm_tis_mmio_write_release_locty(locty);
562
563 uint8_t newlocty = TPM_TIS_NO_LOCALITY;
564 /* anybody wants the locality ? */
565 for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
566 if ((s->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
567 trace_tpm_tis_mmio_write_locty_req_use(c);
568 newlocty = c;
569 break;
570 }
571 }
572 trace_tpm_tis_mmio_write_next_locty(newlocty);
573
574 if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
575 set_new_locty = 0;
576 tpm_tis_prep_abort(s, locty, newlocty);
577 } else {
578 active_locty = TPM_TIS_NO_LOCALITY;
579 }
580 } else {
581 /* not currently the owner; clear a pending request */
582 s->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
583 }
584 }
585
586 if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
587 s->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
588 }
589
590 if ((val & TPM_TIS_ACCESS_SEIZE)) {
591 /*
592 * allow seize if a locality is active and the requesting
593 * locality is higher than the one that's active
594 * OR
595 * allow seize for requesting locality if no locality is
596 * active
597 */
598 while ((TPM_TIS_IS_VALID_LOCTY(s->active_locty) &&
599 locty > s->active_locty) ||
600 !TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
601 bool higher_seize = FALSE;
602
603 /* already a pending SEIZE ? */
604 if ((s->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
605 break;
606 }
607
608 /* check for ongoing seize by a higher locality */
609 for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
610 if ((s->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
611 higher_seize = TRUE;
612 break;
613 }
614 }
615
616 if (higher_seize) {
617 break;
618 }
619
620 /* cancel any seize by a lower locality */
621 for (l = 0; l < locty - 1; l++) {
622 s->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
623 }
624
625 s->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
626
627 trace_tpm_tis_mmio_write_locty_seized(locty, s->active_locty);
628 trace_tpm_tis_mmio_write_init_abort();
629
630 set_new_locty = 0;
631 tpm_tis_prep_abort(s, s->active_locty, locty);
632 break;
633 }
634 }
635
636 if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
637 if (s->active_locty != locty) {
638 if (TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
639 s->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
640 } else {
641 /* no locality active -> make this one active now */
642 active_locty = locty;
643 }
644 }
645 }
646
647 if (set_new_locty) {
648 tpm_tis_new_active_locality(s, active_locty);
649 }
650
651 break;
652 case TPM_TIS_REG_INT_ENABLE:
653 if (s->active_locty != locty) {
654 break;
655 }
656
657 s->loc[locty].inte &= mask;
658 s->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED |
659 TPM_TIS_INT_POLARITY_MASK |
660 TPM_TIS_INTERRUPTS_SUPPORTED));
661 break;
662 case TPM_TIS_REG_INT_VECTOR:
663 /* hard wired -- ignore */
664 break;
665 case TPM_TIS_REG_INT_STATUS:
666 if (s->active_locty != locty) {
667 break;
668 }
669
670 /* clearing of interrupt flags */
671 if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
672 (s->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
673 s->loc[locty].ints &= ~val;
674 if (s->loc[locty].ints == 0) {
675 qemu_irq_lower(s->irq);
676 trace_tpm_tis_mmio_write_lowering_irq();
677 }
678 }
679 s->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
680 break;
681 case TPM_TIS_REG_STS:
682 if (s->active_locty != locty) {
683 break;
684 }
685
686 if (s->be_tpm_version == TPM_VERSION_2_0) {
687 /* some flags that are only supported for TPM 2 */
688 if (val & TPM_TIS_STS_COMMAND_CANCEL) {
689 if (s->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
690 /*
691 * request the backend to cancel. Some backends may not
692 * support it
693 */
694 tpm_backend_cancel_cmd(s->be_driver);
695 }
696 }
697
698 if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) {
699 if (locty == 3 || locty == 4) {
700 tpm_backend_reset_tpm_established_flag(s->be_driver, locty);
701 }
702 }
703 }
704
705 val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
706 TPM_TIS_STS_RESPONSE_RETRY);
707
708 if (val == TPM_TIS_STS_COMMAND_READY) {
709 switch (s->loc[locty].state) {
710
711 case TPM_TIS_STATE_READY:
712 s->rw_offset = 0;
713 break;
714
715 case TPM_TIS_STATE_IDLE:
716 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_COMMAND_READY);
717 s->loc[locty].state = TPM_TIS_STATE_READY;
718 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
719 break;
720
721 case TPM_TIS_STATE_EXECUTION:
722 case TPM_TIS_STATE_RECEPTION:
723 /* abort currently running command */
724 trace_tpm_tis_mmio_write_init_abort();
725 tpm_tis_prep_abort(s, locty, locty);
726 break;
727
728 case TPM_TIS_STATE_COMPLETION:
729 s->rw_offset = 0;
730 /* shortcut to ready state with C/R set */
731 s->loc[locty].state = TPM_TIS_STATE_READY;
732 if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
733 tpm_tis_sts_set(&s->loc[locty],
734 TPM_TIS_STS_COMMAND_READY);
735 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
736 }
737 s->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
738 break;
739
740 }
741 } else if (val == TPM_TIS_STS_TPM_GO) {
742 switch (s->loc[locty].state) {
743 case TPM_TIS_STATE_RECEPTION:
744 if ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
745 tpm_tis_tpm_send(s, locty);
746 }
747 break;
748 default:
749 /* ignore */
750 break;
751 }
752 } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
753 switch (s->loc[locty].state) {
754 case TPM_TIS_STATE_COMPLETION:
755 s->rw_offset = 0;
756 tpm_tis_sts_set(&s->loc[locty],
757 TPM_TIS_STS_VALID|
758 TPM_TIS_STS_DATA_AVAILABLE);
759 break;
760 default:
761 /* ignore */
762 break;
763 }
764 }
765 break;
766 case TPM_TIS_REG_DATA_FIFO:
767 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
768 /* data fifo */
769 if (s->active_locty != locty) {
770 break;
771 }
772
773 if (s->loc[locty].state == TPM_TIS_STATE_IDLE ||
774 s->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
775 s->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
776 /* drop the byte */
777 } else {
778 trace_tpm_tis_mmio_write_data2send(val, size);
779 if (s->loc[locty].state == TPM_TIS_STATE_READY) {
780 s->loc[locty].state = TPM_TIS_STATE_RECEPTION;
781 tpm_tis_sts_set(&s->loc[locty],
782 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
783 }
784
785 val >>= shift;
786 if (size > 4 - (addr & 0x3)) {
787 /* prevent access beyond FIFO */
788 size = 4 - (addr & 0x3);
789 }
790
791 while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {
792 if (s->rw_offset < s->be_buffer_size) {
793 s->buffer[s->rw_offset++] =
794 (uint8_t)val;
795 val >>= 8;
796 size--;
797 } else {
798 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
799 }
800 }
801
802 /* check for complete packet */
803 if (s->rw_offset > 5 &&
804 (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
805 /* we have a packet length - see if we have all of it */
806 bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID);
807
808 len = tpm_cmd_get_size(&s->buffer);
809 if (len > s->rw_offset) {
810 tpm_tis_sts_set(&s->loc[locty],
811 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
812 } else {
813 /* packet complete */
814 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
815 }
816 if (need_irq) {
817 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
818 }
819 }
820 }
821 break;
822 case TPM_TIS_REG_INTERFACE_ID:
823 if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) {
824 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
825 s->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK;
826 }
827 }
828 break;
829 }
830 }
831
832 static const MemoryRegionOps tpm_tis_memory_ops = {
833 .read = tpm_tis_mmio_read,
834 .write = tpm_tis_mmio_write,
835 .endianness = DEVICE_LITTLE_ENDIAN,
836 .valid = {
837 .min_access_size = 1,
838 .max_access_size = 4,
839 },
840 };
841
842 /*
843 * Get the TPMVersion of the backend device being used
844 */
845 static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti)
846 {
847 TPMState *s = TPM(ti);
848
849 if (tpm_backend_had_startup_error(s->be_driver)) {
850 return TPM_VERSION_UNSPEC;
851 }
852
853 return tpm_backend_get_tpm_version(s->be_driver);
854 }
855
856 /*
857 * This function is called when the machine starts, resets or due to
858 * S3 resume.
859 */
860 static void tpm_tis_reset(DeviceState *dev)
861 {
862 TPMState *s = TPM(dev);
863 int c;
864
865 s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
866 s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
867 TPM_TIS_BUFFER_MAX);
868
869 tpm_backend_reset(s->be_driver);
870
871 s->active_locty = TPM_TIS_NO_LOCALITY;
872 s->next_locty = TPM_TIS_NO_LOCALITY;
873 s->aborting_locty = TPM_TIS_NO_LOCALITY;
874
875 for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
876 s->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
877 switch (s->be_tpm_version) {
878 case TPM_VERSION_UNSPEC:
879 break;
880 case TPM_VERSION_1_2:
881 s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2;
882 s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3;
883 break;
884 case TPM_VERSION_2_0:
885 s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0;
886 s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0;
887 break;
888 }
889 s->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
890 s->loc[c].ints = 0;
891 s->loc[c].state = TPM_TIS_STATE_IDLE;
892
893 s->rw_offset = 0;
894 }
895
896 tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size);
897 }
898
899 /* persistent state handling */
900
901 static int tpm_tis_pre_save(void *opaque)
902 {
903 TPMState *s = opaque;
904 uint8_t locty = s->active_locty;
905
906 trace_tpm_tis_pre_save(locty, s->rw_offset);
907
908 if (DEBUG_TIS) {
909 tpm_tis_dump_state(opaque, 0);
910 }
911
912 /*
913 * Synchronize with backend completion.
914 */
915 tpm_backend_finish_sync(s->be_driver);
916
917 return 0;
918 }
919
920 static const VMStateDescription vmstate_locty = {
921 .name = "tpm-tis/locty",
922 .version_id = 0,
923 .fields = (VMStateField[]) {
924 VMSTATE_UINT32(state, TPMLocality),
925 VMSTATE_UINT32(inte, TPMLocality),
926 VMSTATE_UINT32(ints, TPMLocality),
927 VMSTATE_UINT8(access, TPMLocality),
928 VMSTATE_UINT32(sts, TPMLocality),
929 VMSTATE_UINT32(iface_id, TPMLocality),
930 VMSTATE_END_OF_LIST(),
931 }
932 };
933
934 static const VMStateDescription vmstate_tpm_tis = {
935 .name = "tpm-tis",
936 .version_id = 0,
937 .pre_save = tpm_tis_pre_save,
938 .fields = (VMStateField[]) {
939 VMSTATE_BUFFER(buffer, TPMState),
940 VMSTATE_UINT16(rw_offset, TPMState),
941 VMSTATE_UINT8(active_locty, TPMState),
942 VMSTATE_UINT8(aborting_locty, TPMState),
943 VMSTATE_UINT8(next_locty, TPMState),
944
945 VMSTATE_STRUCT_ARRAY(loc, TPMState, TPM_TIS_NUM_LOCALITIES, 0,
946 vmstate_locty, TPMLocality),
947
948 VMSTATE_END_OF_LIST()
949 }
950 };
951
952 static Property tpm_tis_properties[] = {
953 DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ),
954 DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver),
955 DEFINE_PROP_END_OF_LIST(),
956 };
957
958 static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
959 {
960 TPMState *s = TPM(dev);
961
962 if (!tpm_find()) {
963 error_setg(errp, "at most one TPM device is permitted");
964 return;
965 }
966
967 if (!s->be_driver) {
968 error_setg(errp, "'tpmdev' property is required");
969 return;
970 }
971 if (s->irq_num > 15) {
972 error_setg(errp, "IRQ %d is outside valid range of 0 to 15",
973 s->irq_num);
974 return;
975 }
976
977 isa_init_irq(&s->busdev, &s->irq, s->irq_num);
978
979 memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
980 TPM_TIS_ADDR_BASE, &s->mmio);
981 }
982
983 static void tpm_tis_initfn(Object *obj)
984 {
985 TPMState *s = TPM(obj);
986
987 memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
988 s, "tpm-tis-mmio",
989 TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
990 }
991
992 static void tpm_tis_class_init(ObjectClass *klass, void *data)
993 {
994 DeviceClass *dc = DEVICE_CLASS(klass);
995 TPMIfClass *tc = TPM_IF_CLASS(klass);
996
997 dc->realize = tpm_tis_realizefn;
998 dc->props = tpm_tis_properties;
999 dc->reset = tpm_tis_reset;
1000 dc->vmsd = &vmstate_tpm_tis;
1001 tc->model = TPM_MODEL_TPM_TIS;
1002 tc->get_version = tpm_tis_get_tpm_version;
1003 tc->request_completed = tpm_tis_request_completed;
1004 }
1005
1006 static const TypeInfo tpm_tis_info = {
1007 .name = TYPE_TPM_TIS,
1008 .parent = TYPE_ISA_DEVICE,
1009 .instance_size = sizeof(TPMState),
1010 .instance_init = tpm_tis_initfn,
1011 .class_init = tpm_tis_class_init,
1012 .interfaces = (InterfaceInfo[]) {
1013 { TYPE_TPM_IF },
1014 { }
1015 }
1016 };
1017
1018 static void tpm_tis_register(void)
1019 {
1020 type_register_static(&tpm_tis_info);
1021 }
1022
1023 type_init(tpm_tis_register)