1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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
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
44typedef 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
53typedef 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
62typedef 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
91
92static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
93 unsigned size);
94
95
96
97static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
98{
99 return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
100}
101
102static 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
120
121
122
123
124
125
126
127
128
129
130
131static 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
139
140static 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
149
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
165static 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
179static 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
195static 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
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
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
236static void tpm_tis_abort(TPMState *s, uint8_t locty)
237{
238 s->rw_offset = 0;
239
240 trace_tpm_tis_abort(s->next_locty);
241
242
243
244
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
254 tpm_tis_new_active_locality(s, s->next_locty);
255
256 s->next_locty = TPM_TIS_NO_LOCALITY;
257
258 s->aborting_locty = TPM_TIS_NO_LOCALITY;
259}
260
261
262static 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;
269 s->next_locty = newlocty;
270
271
272
273
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
279
280
281 tpm_backend_cancel_cmd(s->be_driver);
282 return;
283 }
284 }
285
286 tpm_tis_abort(s, locty);
287}
288
289
290
291
292static 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 assert(TPM_TIS_IS_VALID_LOCTY(locty));
299
300 if (s->cmd.selftest_done) {
301 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
302 s->loc[l].sts |= TPM_TIS_STS_SELFTEST_DONE;
303 }
304 }
305
306
307 tpm_tis_sts_set(&s->loc[locty],
308 TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
309 s->loc[locty].state = TPM_TIS_STATE_COMPLETION;
310 s->rw_offset = 0;
311
312 if (DEBUG_TIS) {
313 tpm_tis_show_buffer(s->buffer, s->be_buffer_size,
314 "tpm_tis: From TPM");
315 }
316
317 if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) {
318 tpm_tis_abort(s, locty);
319 }
320
321 tpm_tis_raise_irq(s, locty,
322 TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
323}
324
325
326
327
328static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
329{
330 uint32_t ret = TPM_TIS_NO_DATA_BYTE;
331 uint16_t len;
332
333 if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
334 len = MIN(tpm_cmd_get_size(&s->buffer),
335 s->be_buffer_size);
336
337 ret = s->buffer[s->rw_offset++];
338 if (s->rw_offset >= len) {
339
340 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
341 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
342 }
343 trace_tpm_tis_data_read(ret, s->rw_offset - 1);
344 }
345
346 return ret;
347}
348
349#ifdef DEBUG_TIS
350static void tpm_tis_dump_state(void *opaque, hwaddr addr)
351{
352 static const unsigned regs[] = {
353 TPM_TIS_REG_ACCESS,
354 TPM_TIS_REG_INT_ENABLE,
355 TPM_TIS_REG_INT_VECTOR,
356 TPM_TIS_REG_INT_STATUS,
357 TPM_TIS_REG_INTF_CAPABILITY,
358 TPM_TIS_REG_STS,
359 TPM_TIS_REG_DID_VID,
360 TPM_TIS_REG_RID,
361 0xfff};
362 int idx;
363 uint8_t locty = tpm_tis_locality_from_addr(addr);
364 hwaddr base = addr & ~0xfff;
365 TPMState *s = opaque;
366
367 printf("tpm_tis: active locality : %d\n"
368 "tpm_tis: state of locality %d : %d\n"
369 "tpm_tis: register dump:\n",
370 s->active_locty,
371 locty, s->loc[locty].state);
372
373 for (idx = 0; regs[idx] != 0xfff; idx++) {
374 printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
375 (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
376 }
377
378 printf("tpm_tis: r/w offset : %d\n"
379 "tpm_tis: result buffer : ",
380 s->rw_offset);
381 for (idx = 0;
382 idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size);
383 idx++) {
384 printf("%c%02x%s",
385 s->rw_offset == idx ? '>' : ' ',
386 s->buffer[idx],
387 ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
388 }
389 printf("\n");
390}
391#endif
392
393
394
395
396
397static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
398 unsigned size)
399{
400 TPMState *s = opaque;
401 uint16_t offset = addr & 0xffc;
402 uint8_t shift = (addr & 0x3) * 8;
403 uint32_t val = 0xffffffff;
404 uint8_t locty = tpm_tis_locality_from_addr(addr);
405 uint32_t avail;
406 uint8_t v;
407
408 if (tpm_backend_had_startup_error(s->be_driver)) {
409 return 0;
410 }
411
412 switch (offset) {
413 case TPM_TIS_REG_ACCESS:
414
415 val = s->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
416
417 if (tpm_tis_check_request_use_except(s, locty)) {
418 val |= TPM_TIS_ACCESS_PENDING_REQUEST;
419 }
420 val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
421 break;
422 case TPM_TIS_REG_INT_ENABLE:
423 val = s->loc[locty].inte;
424 break;
425 case TPM_TIS_REG_INT_VECTOR:
426 val = s->irq_num;
427 break;
428 case TPM_TIS_REG_INT_STATUS:
429 val = s->loc[locty].ints;
430 break;
431 case TPM_TIS_REG_INTF_CAPABILITY:
432 switch (s->be_tpm_version) {
433 case TPM_VERSION_UNSPEC:
434 val = 0;
435 break;
436 case TPM_VERSION_1_2:
437 val = TPM_TIS_CAPABILITIES_SUPPORTED1_3;
438 break;
439 case TPM_VERSION_2_0:
440 val = TPM_TIS_CAPABILITIES_SUPPORTED2_0;
441 break;
442 }
443 break;
444 case TPM_TIS_REG_STS:
445 if (s->active_locty == locty) {
446 if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
447 val = TPM_TIS_BURST_COUNT(
448 MIN(tpm_cmd_get_size(&s->buffer),
449 s->be_buffer_size)
450 - s->rw_offset) | s->loc[locty].sts;
451 } else {
452 avail = s->be_buffer_size - s->rw_offset;
453
454
455
456
457 if (size == 1 && avail > 0xff) {
458 avail = 0xff;
459 }
460 val = TPM_TIS_BURST_COUNT(avail) | s->loc[locty].sts;
461 }
462 }
463 break;
464 case TPM_TIS_REG_DATA_FIFO:
465 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
466 if (s->active_locty == locty) {
467 if (size > 4 - (addr & 0x3)) {
468
469 size = 4 - (addr & 0x3);
470 }
471 val = 0;
472 shift = 0;
473 while (size > 0) {
474 switch (s->loc[locty].state) {
475 case TPM_TIS_STATE_COMPLETION:
476 v = tpm_tis_data_read(s, locty);
477 break;
478 default:
479 v = TPM_TIS_NO_DATA_BYTE;
480 break;
481 }
482 val |= (v << shift);
483 shift += 8;
484 size--;
485 }
486 shift = 0;
487 }
488 break;
489 case TPM_TIS_REG_INTERFACE_ID:
490 val = s->loc[locty].iface_id;
491 break;
492 case TPM_TIS_REG_DID_VID:
493 val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
494 break;
495 case TPM_TIS_REG_RID:
496 val = TPM_TIS_TPM_RID;
497 break;
498#ifdef DEBUG_TIS
499 case TPM_TIS_REG_DEBUG:
500 tpm_tis_dump_state(opaque, addr);
501 break;
502#endif
503 }
504
505 if (shift) {
506 val >>= shift;
507 }
508
509 trace_tpm_tis_mmio_read(size, addr, val);
510
511 return val;
512}
513
514
515
516
517
518static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
519 uint64_t val, unsigned size)
520{
521 TPMState *s = opaque;
522 uint16_t off = addr & 0xffc;
523 uint8_t shift = (addr & 0x3) * 8;
524 uint8_t locty = tpm_tis_locality_from_addr(addr);
525 uint8_t active_locty, l;
526 int c, set_new_locty = 1;
527 uint16_t len;
528 uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);
529
530 trace_tpm_tis_mmio_write(size, addr, val);
531
532 if (locty == 4) {
533 trace_tpm_tis_mmio_write_locty4();
534 return;
535 }
536
537 if (tpm_backend_had_startup_error(s->be_driver)) {
538 return;
539 }
540
541 val &= mask;
542
543 if (shift) {
544 val <<= shift;
545 mask <<= shift;
546 }
547
548 mask ^= 0xffffffff;
549
550 switch (off) {
551 case TPM_TIS_REG_ACCESS:
552
553 if ((val & TPM_TIS_ACCESS_SEIZE)) {
554 val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
555 TPM_TIS_ACCESS_ACTIVE_LOCALITY);
556 }
557
558 active_locty = s->active_locty;
559
560 if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
561
562 if (s->active_locty == locty) {
563 trace_tpm_tis_mmio_write_release_locty(locty);
564
565 uint8_t newlocty = TPM_TIS_NO_LOCALITY;
566
567 for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
568 if ((s->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
569 trace_tpm_tis_mmio_write_locty_req_use(c);
570 newlocty = c;
571 break;
572 }
573 }
574 trace_tpm_tis_mmio_write_next_locty(newlocty);
575
576 if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
577 set_new_locty = 0;
578 tpm_tis_prep_abort(s, locty, newlocty);
579 } else {
580 active_locty = TPM_TIS_NO_LOCALITY;
581 }
582 } else {
583
584 s->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
585 }
586 }
587
588 if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
589 s->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
590 }
591
592 if ((val & TPM_TIS_ACCESS_SEIZE)) {
593
594
595
596
597
598
599
600 while ((TPM_TIS_IS_VALID_LOCTY(s->active_locty) &&
601 locty > s->active_locty) ||
602 !TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
603 bool higher_seize = FALSE;
604
605
606 if ((s->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
607 break;
608 }
609
610
611 for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
612 if ((s->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
613 higher_seize = TRUE;
614 break;
615 }
616 }
617
618 if (higher_seize) {
619 break;
620 }
621
622
623 for (l = 0; l < locty; l++) {
624 s->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
625 }
626
627 s->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
628
629 trace_tpm_tis_mmio_write_locty_seized(locty, s->active_locty);
630 trace_tpm_tis_mmio_write_init_abort();
631
632 set_new_locty = 0;
633 tpm_tis_prep_abort(s, s->active_locty, locty);
634 break;
635 }
636 }
637
638 if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
639 if (s->active_locty != locty) {
640 if (TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
641 s->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
642 } else {
643
644 active_locty = locty;
645 }
646 }
647 }
648
649 if (set_new_locty) {
650 tpm_tis_new_active_locality(s, active_locty);
651 }
652
653 break;
654 case TPM_TIS_REG_INT_ENABLE:
655 if (s->active_locty != locty) {
656 break;
657 }
658
659 s->loc[locty].inte &= mask;
660 s->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED |
661 TPM_TIS_INT_POLARITY_MASK |
662 TPM_TIS_INTERRUPTS_SUPPORTED));
663 break;
664 case TPM_TIS_REG_INT_VECTOR:
665
666 break;
667 case TPM_TIS_REG_INT_STATUS:
668 if (s->active_locty != locty) {
669 break;
670 }
671
672
673 if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
674 (s->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
675 s->loc[locty].ints &= ~val;
676 if (s->loc[locty].ints == 0) {
677 qemu_irq_lower(s->irq);
678 trace_tpm_tis_mmio_write_lowering_irq();
679 }
680 }
681 s->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
682 break;
683 case TPM_TIS_REG_STS:
684 if (s->active_locty != locty) {
685 break;
686 }
687
688 if (s->be_tpm_version == TPM_VERSION_2_0) {
689
690 if (val & TPM_TIS_STS_COMMAND_CANCEL) {
691 if (s->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
692
693
694
695
696 tpm_backend_cancel_cmd(s->be_driver);
697 }
698 }
699
700 if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) {
701 if (locty == 3 || locty == 4) {
702 tpm_backend_reset_tpm_established_flag(s->be_driver, locty);
703 }
704 }
705 }
706
707 val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
708 TPM_TIS_STS_RESPONSE_RETRY);
709
710 if (val == TPM_TIS_STS_COMMAND_READY) {
711 switch (s->loc[locty].state) {
712
713 case TPM_TIS_STATE_READY:
714 s->rw_offset = 0;
715 break;
716
717 case TPM_TIS_STATE_IDLE:
718 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_COMMAND_READY);
719 s->loc[locty].state = TPM_TIS_STATE_READY;
720 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
721 break;
722
723 case TPM_TIS_STATE_EXECUTION:
724 case TPM_TIS_STATE_RECEPTION:
725
726 trace_tpm_tis_mmio_write_init_abort();
727 tpm_tis_prep_abort(s, locty, locty);
728 break;
729
730 case TPM_TIS_STATE_COMPLETION:
731 s->rw_offset = 0;
732
733 s->loc[locty].state = TPM_TIS_STATE_READY;
734 if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
735 tpm_tis_sts_set(&s->loc[locty],
736 TPM_TIS_STS_COMMAND_READY);
737 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
738 }
739 s->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
740 break;
741
742 }
743 } else if (val == TPM_TIS_STS_TPM_GO) {
744 switch (s->loc[locty].state) {
745 case TPM_TIS_STATE_RECEPTION:
746 if ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
747 tpm_tis_tpm_send(s, locty);
748 }
749 break;
750 default:
751
752 break;
753 }
754 } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
755 switch (s->loc[locty].state) {
756 case TPM_TIS_STATE_COMPLETION:
757 s->rw_offset = 0;
758 tpm_tis_sts_set(&s->loc[locty],
759 TPM_TIS_STS_VALID|
760 TPM_TIS_STS_DATA_AVAILABLE);
761 break;
762 default:
763
764 break;
765 }
766 }
767 break;
768 case TPM_TIS_REG_DATA_FIFO:
769 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
770
771 if (s->active_locty != locty) {
772 break;
773 }
774
775 if (s->loc[locty].state == TPM_TIS_STATE_IDLE ||
776 s->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
777 s->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
778
779 } else {
780 trace_tpm_tis_mmio_write_data2send(val, size);
781 if (s->loc[locty].state == TPM_TIS_STATE_READY) {
782 s->loc[locty].state = TPM_TIS_STATE_RECEPTION;
783 tpm_tis_sts_set(&s->loc[locty],
784 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
785 }
786
787 val >>= shift;
788 if (size > 4 - (addr & 0x3)) {
789
790 size = 4 - (addr & 0x3);
791 }
792
793 while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {
794 if (s->rw_offset < s->be_buffer_size) {
795 s->buffer[s->rw_offset++] =
796 (uint8_t)val;
797 val >>= 8;
798 size--;
799 } else {
800 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
801 }
802 }
803
804
805 if (s->rw_offset > 5 &&
806 (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
807
808 bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID);
809
810 len = tpm_cmd_get_size(&s->buffer);
811 if (len > s->rw_offset) {
812 tpm_tis_sts_set(&s->loc[locty],
813 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
814 } else {
815
816 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
817 }
818 if (need_irq) {
819 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
820 }
821 }
822 }
823 break;
824 case TPM_TIS_REG_INTERFACE_ID:
825 if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) {
826 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
827 s->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK;
828 }
829 }
830 break;
831 }
832}
833
834static const MemoryRegionOps tpm_tis_memory_ops = {
835 .read = tpm_tis_mmio_read,
836 .write = tpm_tis_mmio_write,
837 .endianness = DEVICE_LITTLE_ENDIAN,
838 .valid = {
839 .min_access_size = 1,
840 .max_access_size = 4,
841 },
842};
843
844
845
846
847static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti)
848{
849 TPMState *s = TPM(ti);
850
851 if (tpm_backend_had_startup_error(s->be_driver)) {
852 return TPM_VERSION_UNSPEC;
853 }
854
855 return tpm_backend_get_tpm_version(s->be_driver);
856}
857
858
859
860
861
862static void tpm_tis_reset(DeviceState *dev)
863{
864 TPMState *s = TPM(dev);
865 int c;
866
867 s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
868 s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
869 TPM_TIS_BUFFER_MAX);
870
871 tpm_backend_reset(s->be_driver);
872
873 s->active_locty = TPM_TIS_NO_LOCALITY;
874 s->next_locty = TPM_TIS_NO_LOCALITY;
875 s->aborting_locty = TPM_TIS_NO_LOCALITY;
876
877 for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
878 s->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
879 switch (s->be_tpm_version) {
880 case TPM_VERSION_UNSPEC:
881 break;
882 case TPM_VERSION_1_2:
883 s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2;
884 s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3;
885 break;
886 case TPM_VERSION_2_0:
887 s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0;
888 s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0;
889 break;
890 }
891 s->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
892 s->loc[c].ints = 0;
893 s->loc[c].state = TPM_TIS_STATE_IDLE;
894
895 s->rw_offset = 0;
896 }
897
898 if (tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size) < 0) {
899 exit(1);
900 }
901}
902
903
904
905static int tpm_tis_pre_save(void *opaque)
906{
907 TPMState *s = opaque;
908 uint8_t locty = s->active_locty;
909
910 trace_tpm_tis_pre_save(locty, s->rw_offset);
911
912 if (DEBUG_TIS) {
913 tpm_tis_dump_state(opaque, 0);
914 }
915
916
917
918
919 tpm_backend_finish_sync(s->be_driver);
920
921 return 0;
922}
923
924static const VMStateDescription vmstate_locty = {
925 .name = "tpm-tis/locty",
926 .version_id = 0,
927 .fields = (VMStateField[]) {
928 VMSTATE_UINT32(state, TPMLocality),
929 VMSTATE_UINT32(inte, TPMLocality),
930 VMSTATE_UINT32(ints, TPMLocality),
931 VMSTATE_UINT8(access, TPMLocality),
932 VMSTATE_UINT32(sts, TPMLocality),
933 VMSTATE_UINT32(iface_id, TPMLocality),
934 VMSTATE_END_OF_LIST(),
935 }
936};
937
938static const VMStateDescription vmstate_tpm_tis = {
939 .name = "tpm-tis",
940 .version_id = 0,
941 .pre_save = tpm_tis_pre_save,
942 .fields = (VMStateField[]) {
943 VMSTATE_BUFFER(buffer, TPMState),
944 VMSTATE_UINT16(rw_offset, TPMState),
945 VMSTATE_UINT8(active_locty, TPMState),
946 VMSTATE_UINT8(aborting_locty, TPMState),
947 VMSTATE_UINT8(next_locty, TPMState),
948
949 VMSTATE_STRUCT_ARRAY(loc, TPMState, TPM_TIS_NUM_LOCALITIES, 0,
950 vmstate_locty, TPMLocality),
951
952 VMSTATE_END_OF_LIST()
953 }
954};
955
956static Property tpm_tis_properties[] = {
957 DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ),
958 DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver),
959 DEFINE_PROP_END_OF_LIST(),
960};
961
962static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
963{
964 TPMState *s = TPM(dev);
965
966 if (!tpm_find()) {
967 error_setg(errp, "at most one TPM device is permitted");
968 return;
969 }
970
971 if (!s->be_driver) {
972 error_setg(errp, "'tpmdev' property is required");
973 return;
974 }
975 if (s->irq_num > 15) {
976 error_setg(errp, "IRQ %d is outside valid range of 0 to 15",
977 s->irq_num);
978 return;
979 }
980
981 isa_init_irq(&s->busdev, &s->irq, s->irq_num);
982
983 memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
984 TPM_TIS_ADDR_BASE, &s->mmio);
985}
986
987static void tpm_tis_initfn(Object *obj)
988{
989 TPMState *s = TPM(obj);
990
991 memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
992 s, "tpm-tis-mmio",
993 TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
994}
995
996static void tpm_tis_class_init(ObjectClass *klass, void *data)
997{
998 DeviceClass *dc = DEVICE_CLASS(klass);
999 TPMIfClass *tc = TPM_IF_CLASS(klass);
1000
1001 dc->realize = tpm_tis_realizefn;
1002 dc->props = tpm_tis_properties;
1003 dc->reset = tpm_tis_reset;
1004 dc->vmsd = &vmstate_tpm_tis;
1005 tc->model = TPM_MODEL_TPM_TIS;
1006 tc->get_version = tpm_tis_get_tpm_version;
1007 tc->request_completed = tpm_tis_request_completed;
1008}
1009
1010static const TypeInfo tpm_tis_info = {
1011 .name = TYPE_TPM_TIS,
1012 .parent = TYPE_ISA_DEVICE,
1013 .instance_size = sizeof(TPMState),
1014 .instance_init = tpm_tis_initfn,
1015 .class_init = tpm_tis_class_init,
1016 .interfaces = (InterfaceInfo[]) {
1017 { TYPE_TPM_IF },
1018 { }
1019 }
1020};
1021
1022static void tpm_tis_register(void)
1023{
1024 type_register_static(&tpm_tis_info);
1025}
1026
1027type_init(tpm_tis_register)
1028