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