xref: /qemu/hw/tpm/tpm_tis_common.c (revision 2eae8c7516a99c1309199df8d88c0f0749fce2cb)
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.21, revision 1.0.
18  * In the developers menu choose the PC Client section then find the TIS
19  * specification.
20  */
21 
22 #include "sysemu/tpm_backend.h"
23 #include "tpm_int.h"
24 #include "sysemu/block-backend.h"
25 #include "exec/address-spaces.h"
26 #include "hw/hw.h"
27 #include "hw/i386/pc.h"
28 #include "hw/pci/pci_ids.h"
29 #include "tpm_tis.h"
30 #include "qemu-common.h"
31 #include "qemu/main-loop.h"
32 
33 /*#define DEBUG_TIS */
34 
35 #ifdef DEBUG_TIS
36 #define DPRINTF(fmt, ...) \
37     do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
38 #else
39 #define DPRINTF(fmt, ...) \
40     do { } while (0)
41 #endif
42 
43 /* whether the STS interrupt is supported */
44 #define RAISE_STS_IRQ
45 
46 /* tis registers */
47 #define TPM_TIS_REG_ACCESS                0x00
48 #define TPM_TIS_REG_INT_ENABLE            0x08
49 #define TPM_TIS_REG_INT_VECTOR            0x0c
50 #define TPM_TIS_REG_INT_STATUS            0x10
51 #define TPM_TIS_REG_INTF_CAPABILITY       0x14
52 #define TPM_TIS_REG_STS                   0x18
53 #define TPM_TIS_REG_DATA_FIFO             0x24
54 #define TPM_TIS_REG_DATA_XFIFO            0x80
55 #define TPM_TIS_REG_DATA_XFIFO_END        0xbc
56 #define TPM_TIS_REG_DID_VID               0xf00
57 #define TPM_TIS_REG_RID                   0xf04
58 
59 /* vendor-specific registers */
60 #define TPM_TIS_REG_DEBUG                 0xf90
61 
62 #define TPM_TIS_STS_VALID                 (1 << 7)
63 #define TPM_TIS_STS_COMMAND_READY         (1 << 6)
64 #define TPM_TIS_STS_TPM_GO                (1 << 5)
65 #define TPM_TIS_STS_DATA_AVAILABLE        (1 << 4)
66 #define TPM_TIS_STS_EXPECT                (1 << 3)
67 #define TPM_TIS_STS_RESPONSE_RETRY        (1 << 1)
68 
69 #define TPM_TIS_BURST_COUNT_SHIFT         8
70 #define TPM_TIS_BURST_COUNT(X) \
71     ((X) << TPM_TIS_BURST_COUNT_SHIFT)
72 
73 #define TPM_TIS_ACCESS_TPM_REG_VALID_STS  (1 << 7)
74 #define TPM_TIS_ACCESS_ACTIVE_LOCALITY    (1 << 5)
75 #define TPM_TIS_ACCESS_BEEN_SEIZED        (1 << 4)
76 #define TPM_TIS_ACCESS_SEIZE              (1 << 3)
77 #define TPM_TIS_ACCESS_PENDING_REQUEST    (1 << 2)
78 #define TPM_TIS_ACCESS_REQUEST_USE        (1 << 1)
79 #define TPM_TIS_ACCESS_TPM_ESTABLISHMENT  (1 << 0)
80 
81 #define TPM_TIS_INT_ENABLED               (1 << 31)
82 #define TPM_TIS_INT_DATA_AVAILABLE        (1 << 0)
83 #define TPM_TIS_INT_STS_VALID             (1 << 1)
84 #define TPM_TIS_INT_LOCALITY_CHANGED      (1 << 2)
85 #define TPM_TIS_INT_COMMAND_READY         (1 << 7)
86 
87 #define TPM_TIS_INT_POLARITY_MASK         (3 << 3)
88 #define TPM_TIS_INT_POLARITY_LOW_LEVEL    (1 << 3)
89 
90 #ifndef RAISE_STS_IRQ
91 
92 #define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
93                                       TPM_TIS_INT_DATA_AVAILABLE   | \
94                                       TPM_TIS_INT_COMMAND_READY)
95 
96 #else
97 
98 #define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
99                                       TPM_TIS_INT_DATA_AVAILABLE   | \
100                                       TPM_TIS_INT_STS_VALID | \
101                                       TPM_TIS_INT_COMMAND_READY)
102 
103 #endif
104 
105 #define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL  (1 << 4) /* support is mandatory */
106 #define TPM_TIS_CAPABILITIES_SUPPORTED   (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
107                                           TPM_TIS_INTERRUPTS_SUPPORTED)
108 
109 #define TPM_TIS_TPM_DID       0x0001
110 #define TPM_TIS_TPM_VID       PCI_VENDOR_ID_IBM
111 #define TPM_TIS_TPM_RID       0x0001
112 
113 #define TPM_TIS_NO_DATA_BYTE  0xff
114 
115 /* local prototypes */
116 
117 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
118                                   unsigned size);
119 
120 /* utility functions */
121 
122 static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
123 {
124     return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
125 }
126 
127 static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
128 {
129     return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
130 }
131 
132 static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
133 {
134 #ifdef DEBUG_TIS
135     uint32_t len, i;
136 
137     len = tpm_tis_get_size_from_buffer(sb);
138     DPRINTF("tpm_tis: %s length = %d\n", string, len);
139     for (i = 0; i < len; i++) {
140         if (i && !(i % 16)) {
141             DPRINTF("\n");
142         }
143         DPRINTF("%.2X ", sb->buffer[i]);
144     }
145     DPRINTF("\n");
146 #endif
147 }
148 
149 /*
150  * Send a request to the TPM.
151  */
152 static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
153 {
154     TPMTISEmuState *tis = &s->s.tis;
155 
156     tpm_tis_show_buffer(&tis->loc[locty].w_buffer, "tpm_tis: To TPM");
157 
158     s->locty_number = locty;
159     s->locty_data = &tis->loc[locty];
160 
161     /*
162      * w_offset serves as length indicator for length of data;
163      * it's reset when the response comes back
164      */
165     tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
166 
167     tpm_backend_deliver_request(s->be_driver);
168 }
169 
170 /* raise an interrupt if allowed */
171 static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
172 {
173     TPMTISEmuState *tis = &s->s.tis;
174 
175     if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
176         return;
177     }
178 
179     if ((tis->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
180         (tis->loc[locty].inte & irqmask)) {
181         DPRINTF("tpm_tis: Raising IRQ for flag %08x\n", irqmask);
182         qemu_irq_raise(s->s.tis.irq);
183         tis->loc[locty].ints |= irqmask;
184     }
185 }
186 
187 static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
188 {
189     uint8_t l;
190 
191     for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
192         if (l == locty) {
193             continue;
194         }
195         if ((s->s.tis.loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
196             return 1;
197         }
198     }
199 
200     return 0;
201 }
202 
203 static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
204 {
205     TPMTISEmuState *tis = &s->s.tis;
206     bool change = (s->s.tis.active_locty != new_active_locty);
207     bool is_seize;
208     uint8_t mask;
209 
210     if (change && TPM_TIS_IS_VALID_LOCTY(s->s.tis.active_locty)) {
211         is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
212                    tis->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
213 
214         if (is_seize) {
215             mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
216         } else {
217             mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
218                      TPM_TIS_ACCESS_REQUEST_USE);
219         }
220         /* reset flags on the old active locality */
221         tis->loc[s->s.tis.active_locty].access &= mask;
222 
223         if (is_seize) {
224             tis->loc[tis->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
225         }
226     }
227 
228     tis->active_locty = new_active_locty;
229 
230     DPRINTF("tpm_tis: Active locality is now %d\n", s->s.tis.active_locty);
231 
232     if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
233         /* set flags on the new active locality */
234         tis->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
235         tis->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
236                                                TPM_TIS_ACCESS_SEIZE);
237     }
238 
239     if (change) {
240         tpm_tis_raise_irq(s, tis->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
241     }
242 }
243 
244 /* abort -- this function switches the locality */
245 static void tpm_tis_abort(TPMState *s, uint8_t locty)
246 {
247     TPMTISEmuState *tis = &s->s.tis;
248 
249     tis->loc[locty].r_offset = 0;
250     tis->loc[locty].w_offset = 0;
251 
252     DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis->next_locty);
253 
254     /*
255      * Need to react differently depending on who's aborting now and
256      * which locality will become active afterwards.
257      */
258     if (tis->aborting_locty == tis->next_locty) {
259         tis->loc[tis->aborting_locty].state = TPM_TIS_STATE_READY;
260         tis->loc[tis->aborting_locty].sts = TPM_TIS_STS_COMMAND_READY;
261         tpm_tis_raise_irq(s, tis->aborting_locty, TPM_TIS_INT_COMMAND_READY);
262     }
263 
264     /* locality after abort is another one than the current one */
265     tpm_tis_new_active_locality(s, tis->next_locty);
266 
267     tis->next_locty = TPM_TIS_NO_LOCALITY;
268     /* nobody's aborting a command anymore */
269     tis->aborting_locty = TPM_TIS_NO_LOCALITY;
270 }
271 
272 /* prepare aborting current command */
273 static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
274 {
275     TPMTISEmuState *tis = &s->s.tis;
276     uint8_t busy_locty;
277 
278     tis->aborting_locty = locty;
279     tis->next_locty = newlocty;  /* locality after successful abort */
280 
281     /*
282      * only abort a command using an interrupt if currently executing
283      * a command AND if there's a valid connection to the vTPM.
284      */
285     for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
286         if (tis->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
287             /*
288              * request the backend to cancel. Some backends may not
289              * support it
290              */
291             tpm_backend_cancel_cmd(s->be_driver);
292             return;
293         }
294     }
295 
296     tpm_tis_abort(s, locty);
297 }
298 
299 static void tpm_tis_receive_bh(void *opaque)
300 {
301     TPMState *s = opaque;
302     TPMTISEmuState *tis = &s->s.tis;
303     uint8_t locty = s->locty_number;
304 
305     tis->loc[locty].sts = TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE;
306     tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
307     tis->loc[locty].r_offset = 0;
308     tis->loc[locty].w_offset = 0;
309 
310     if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) {
311         tpm_tis_abort(s, locty);
312     }
313 
314 #ifndef RAISE_STS_IRQ
315     tpm_tis_raise_irq(s, locty, TPM_TIS_INT_DATA_AVAILABLE);
316 #else
317     tpm_tis_raise_irq(s, locty,
318                       TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
319 #endif
320 }
321 
322 /*
323  * Callback from the TPM to indicate that the response was received.
324  */
325 static void tpm_tis_receive_cb(TPMState *s, uint8_t locty)
326 {
327     TPMTISEmuState *tis = &s->s.tis;
328 
329     assert(s->locty_number == locty);
330 
331     qemu_bh_schedule(tis->bh);
332 }
333 
334 /*
335  * Read a byte of response data
336  */
337 static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
338 {
339     TPMTISEmuState *tis = &s->s.tis;
340     uint32_t ret = TPM_TIS_NO_DATA_BYTE;
341     uint16_t len;
342 
343     if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
344         len = tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
345 
346         ret = tis->loc[locty].r_buffer.buffer[tis->loc[locty].r_offset++];
347         if (tis->loc[locty].r_offset >= len) {
348             /* got last byte */
349             tis->loc[locty].sts = TPM_TIS_STS_VALID;
350 #ifdef RAISE_STS_IRQ
351             tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
352 #endif
353         }
354         DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x   [%d]\n",
355                 ret, tis->loc[locty].r_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     TPMTISEmuState *tis = &s->s.tis;
379 
380     DPRINTF("tpm_tis: active locality      : %d\n"
381             "tpm_tis: state of locality %d : %d\n"
382             "tpm_tis: register dump:\n",
383             tis->active_locty,
384             locty, tis->loc[locty].state);
385 
386     for (idx = 0; regs[idx] != 0xfff; idx++) {
387         DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
388                 (uint32_t)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
389     }
390 
391     DPRINTF("tpm_tis: read offset   : %d\n"
392             "tpm_tis: result buffer : ",
393             tis->loc[locty].r_offset);
394     for (idx = 0;
395          idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
396          idx++) {
397         DPRINTF("%c%02x%s",
398                 tis->loc[locty].r_offset == idx ? '>' : ' ',
399                 tis->loc[locty].r_buffer.buffer[idx],
400                 ((idx & 0xf) == 0xf) ? "\ntpm_tis:                 " : "");
401     }
402     DPRINTF("\n"
403             "tpm_tis: write offset  : %d\n"
404             "tpm_tis: request buffer: ",
405             tis->loc[locty].w_offset);
406     for (idx = 0;
407          idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
408          idx++) {
409         DPRINTF("%c%02x%s",
410                 tis->loc[locty].w_offset == idx ? '>' : ' ',
411                 tis->loc[locty].w_buffer.buffer[idx],
412                 ((idx & 0xf) == 0xf) ? "\ntpm_tis:                 " : "");
413     }
414     DPRINTF("\n");
415 }
416 #endif
417 
418 /*
419  * Read a register of the TIS interface
420  * See specs pages 33-63 for description of the registers
421  */
422 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
423                                   unsigned size)
424 {
425     TPMState *s = opaque;
426     TPMTISEmuState *tis = &s->s.tis;
427     uint16_t offset = addr & 0xffc;
428     uint8_t shift = (addr & 0x3) * 8;
429     uint32_t val = 0xffffffff;
430     uint8_t locty = tpm_tis_locality_from_addr(addr);
431     uint32_t avail;
432     uint8_t v;
433 
434     if (tpm_backend_had_startup_error(s->be_driver)) {
435         return val;
436     }
437 
438     switch (offset) {
439     case TPM_TIS_REG_ACCESS:
440         /* never show the SEIZE flag even though we use it internally */
441         val = tis->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
442         /* the pending flag is always calculated */
443         if (tpm_tis_check_request_use_except(s, locty)) {
444             val |= TPM_TIS_ACCESS_PENDING_REQUEST;
445         }
446         val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
447         break;
448     case TPM_TIS_REG_INT_ENABLE:
449         val = tis->loc[locty].inte;
450         break;
451     case TPM_TIS_REG_INT_VECTOR:
452         val = tis->irq_num;
453         break;
454     case TPM_TIS_REG_INT_STATUS:
455         val = tis->loc[locty].ints;
456         break;
457     case TPM_TIS_REG_INTF_CAPABILITY:
458         val = TPM_TIS_CAPABILITIES_SUPPORTED;
459         break;
460     case TPM_TIS_REG_STS:
461         if (tis->active_locty == locty) {
462             if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
463                 val = TPM_TIS_BURST_COUNT(
464                        tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer)
465                        - tis->loc[locty].r_offset) | tis->loc[locty].sts;
466             } else {
467                 avail = tis->loc[locty].w_buffer.size
468                         - tis->loc[locty].w_offset;
469                 /*
470                  * byte-sized reads should not return 0x00 for 0x100
471                  * available bytes.
472                  */
473                 if (size == 1 && avail > 0xff) {
474                     avail = 0xff;
475                 }
476                 val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts;
477             }
478         }
479         break;
480     case TPM_TIS_REG_DATA_FIFO:
481     case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
482         if (tis->active_locty == locty) {
483             if (size > 4 - (addr & 0x3)) {
484                 /* prevent access beyond FIFO */
485                 size = 4 - (addr & 0x3);
486             }
487             val = 0;
488             shift = 0;
489             while (size > 0) {
490                 switch (tis->loc[locty].state) {
491                 case TPM_TIS_STATE_COMPLETION:
492                     v = tpm_tis_data_read(s, locty);
493                     break;
494                 default:
495                     v = TPM_TIS_NO_DATA_BYTE;
496                     break;
497                 }
498                 val |= (v << shift);
499                 shift += 8;
500                 size--;
501             }
502             shift = 0; /* no more adjustments */
503         }
504         break;
505     case TPM_TIS_REG_DID_VID:
506         val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
507         break;
508     case TPM_TIS_REG_RID:
509         val = TPM_TIS_TPM_RID;
510         break;
511 #ifdef DEBUG_TIS
512     case TPM_TIS_REG_DEBUG:
513         tpm_tis_dump_state(opaque, addr);
514         break;
515 #endif
516     }
517 
518     if (shift) {
519         val >>= shift;
520     }
521 
522     DPRINTF("tpm_tis:  read.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
523 
524     return val;
525 }
526 
527 /*
528  * Write a value to a register of the TIS interface
529  * See specs pages 33-63 for description of the registers
530  */
531 static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
532                                       uint64_t val, unsigned size,
533                                       bool hw_access)
534 {
535     TPMState *s = opaque;
536     TPMTISEmuState *tis = &s->s.tis;
537     uint16_t off = addr & 0xffc;
538     uint8_t shift = (addr & 0x3) * 8;
539     uint8_t locty = tpm_tis_locality_from_addr(addr);
540     uint8_t active_locty, l;
541     int c, set_new_locty = 1;
542     uint16_t len;
543     uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);
544 
545     DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
546 
547     if (locty == 4 && !hw_access) {
548         DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
549         return;
550     }
551 
552     if (tpm_backend_had_startup_error(s->be_driver)) {
553         return;
554     }
555 
556     val &= mask;
557 
558     if (shift) {
559         val <<= shift;
560         mask <<= shift;
561     }
562 
563     mask ^= 0xffffffff;
564 
565     switch (off) {
566     case TPM_TIS_REG_ACCESS:
567 
568         if ((val & TPM_TIS_ACCESS_SEIZE)) {
569             val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
570                      TPM_TIS_ACCESS_ACTIVE_LOCALITY);
571         }
572 
573         active_locty = tis->active_locty;
574 
575         if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
576             /* give up locality if currently owned */
577             if (tis->active_locty == locty) {
578                 DPRINTF("tpm_tis: Releasing locality %d\n", locty);
579 
580                 uint8_t newlocty = TPM_TIS_NO_LOCALITY;
581                 /* anybody wants the locality ? */
582                 for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
583                     if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
584                         DPRINTF("tpm_tis: Locality %d requests use.\n", c);
585                         newlocty = c;
586                         break;
587                     }
588                 }
589                 DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
590                         "Next active locality: %d\n",
591                         newlocty);
592 
593                 if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
594                     set_new_locty = 0;
595                     tpm_tis_prep_abort(s, locty, newlocty);
596                 } else {
597                     active_locty = TPM_TIS_NO_LOCALITY;
598                 }
599             } else {
600                 /* not currently the owner; clear a pending request */
601                 tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
602             }
603         }
604 
605         if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
606             tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
607         }
608 
609         if ((val & TPM_TIS_ACCESS_SEIZE)) {
610             /*
611              * allow seize if a locality is active and the requesting
612              * locality is higher than the one that's active
613              * OR
614              * allow seize for requesting locality if no locality is
615              * active
616              */
617             while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&
618                     locty > tis->active_locty) ||
619                     !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
620                 bool higher_seize = FALSE;
621 
622                 /* already a pending SEIZE ? */
623                 if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
624                     break;
625                 }
626 
627                 /* check for ongoing seize by a higher locality */
628                 for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
629                     if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
630                         higher_seize = TRUE;
631                         break;
632                     }
633                 }
634 
635                 if (higher_seize) {
636                     break;
637                 }
638 
639                 /* cancel any seize by a lower locality */
640                 for (l = 0; l < locty - 1; l++) {
641                     tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
642                 }
643 
644                 tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
645                 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
646                         "Locality %d seized from locality %d\n",
647                         locty, tis->active_locty);
648                 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");
649                 set_new_locty = 0;
650                 tpm_tis_prep_abort(s, tis->active_locty, locty);
651                 break;
652             }
653         }
654 
655         if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
656             if (tis->active_locty != locty) {
657                 if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
658                     tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
659                 } else {
660                     /* no locality active -> make this one active now */
661                     active_locty = locty;
662                 }
663             }
664         }
665 
666         if (set_new_locty) {
667             tpm_tis_new_active_locality(s, active_locty);
668         }
669 
670         break;
671     case TPM_TIS_REG_INT_ENABLE:
672         if (tis->active_locty != locty) {
673             break;
674         }
675 
676         tis->loc[locty].inte &= mask;
677         tis->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED |
678                                         TPM_TIS_INT_POLARITY_MASK |
679                                         TPM_TIS_INTERRUPTS_SUPPORTED));
680         break;
681     case TPM_TIS_REG_INT_VECTOR:
682         /* hard wired -- ignore */
683         break;
684     case TPM_TIS_REG_INT_STATUS:
685         if (tis->active_locty != locty) {
686             break;
687         }
688 
689         /* clearing of interrupt flags */
690         if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
691             (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
692             tis->loc[locty].ints &= ~val;
693             if (tis->loc[locty].ints == 0) {
694                 qemu_irq_lower(tis->irq);
695                 DPRINTF("tpm_tis: Lowering IRQ\n");
696             }
697         }
698         tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
699         break;
700     case TPM_TIS_REG_STS:
701         if (tis->active_locty != locty) {
702             break;
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 (tis->loc[locty].state) {
710 
711             case TPM_TIS_STATE_READY:
712                 tis->loc[locty].w_offset = 0;
713                 tis->loc[locty].r_offset = 0;
714             break;
715 
716             case TPM_TIS_STATE_IDLE:
717                 tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;
718                 tis->loc[locty].state = TPM_TIS_STATE_READY;
719                 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
720             break;
721 
722             case TPM_TIS_STATE_EXECUTION:
723             case TPM_TIS_STATE_RECEPTION:
724                 /* abort currently running command */
725                 DPRINTF("tpm_tis: %s: Initiating abort.\n",
726                         __func__);
727                 tpm_tis_prep_abort(s, locty, locty);
728             break;
729 
730             case TPM_TIS_STATE_COMPLETION:
731                 tis->loc[locty].w_offset = 0;
732                 tis->loc[locty].r_offset = 0;
733                 /* shortcut to ready state with C/R set */
734                 tis->loc[locty].state = TPM_TIS_STATE_READY;
735                 if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
736                     tis->loc[locty].sts   = TPM_TIS_STS_COMMAND_READY;
737                     tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
738                 }
739                 tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
740             break;
741 
742             }
743         } else if (val == TPM_TIS_STS_TPM_GO) {
744             switch (tis->loc[locty].state) {
745             case TPM_TIS_STATE_RECEPTION:
746                 if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
747                     tpm_tis_tpm_send(s, locty);
748                 }
749                 break;
750             default:
751                 /* ignore */
752                 break;
753             }
754         } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
755             switch (tis->loc[locty].state) {
756             case TPM_TIS_STATE_COMPLETION:
757                 tis->loc[locty].r_offset = 0;
758                 tis->loc[locty].sts = TPM_TIS_STS_VALID |
759                                       TPM_TIS_STS_DATA_AVAILABLE;
760                 break;
761             default:
762                 /* ignore */
763                 break;
764             }
765         }
766         break;
767     case TPM_TIS_REG_DATA_FIFO:
768     case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
769         /* data fifo */
770         if (tis->active_locty != locty) {
771             break;
772         }
773 
774         if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||
775             tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
776             tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
777             /* drop the byte */
778         } else {
779             DPRINTF("tpm_tis: Data to send to TPM: %08x (size=%d)\n",
780                     val, size);
781             if (tis->loc[locty].state == TPM_TIS_STATE_READY) {
782                 tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;
783                 tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID;
784             }
785 
786             val >>= shift;
787             if (size > 4 - (addr & 0x3)) {
788                 /* prevent access beyond FIFO */
789                 size = 4 - (addr & 0x3);
790             }
791 
792             while ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {
793                 if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {
794                     tis->loc[locty].w_buffer.
795                         buffer[tis->loc[locty].w_offset++] = (uint8_t)val;
796                     val >>= 8;
797                     size--;
798                 } else {
799                     tis->loc[locty].sts = TPM_TIS_STS_VALID;
800                 }
801             }
802 
803             /* check for complete packet */
804             if (tis->loc[locty].w_offset > 5 &&
805                 (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
806                 /* we have a packet length - see if we have all of it */
807 #ifdef RAISE_STS_IRQ
808                 bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);
809 #endif
810                 len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
811                 if (len > tis->loc[locty].w_offset) {
812                     tis->loc[locty].sts = TPM_TIS_STS_EXPECT |
813                                           TPM_TIS_STS_VALID;
814                 } else {
815                     /* packet complete */
816                     tis->loc[locty].sts = TPM_TIS_STS_VALID;
817                 }
818 #ifdef RAISE_STS_IRQ
819                 if (needIrq) {
820                     tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
821                 }
822 #endif
823             }
824         }
825         break;
826     }
827 }
828 
829 static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
830                                uint64_t val, unsigned size)
831 {
832     return tpm_tis_mmio_write_intern(opaque, addr, val, size, false);
833 }
834 
835 static const MemoryRegionOps tpm_tis_memory_ops = {
836     .read = tpm_tis_mmio_read,
837     .write = tpm_tis_mmio_write,
838     .endianness = DEVICE_LITTLE_ENDIAN,
839     .valid = {
840         .min_access_size = 1,
841         .max_access_size = 4,
842     },
843 };
844 
845 static int tpm_tis_do_startup_tpm(TPMState *s)
846 {
847     return tpm_backend_startup_tpm(s->be_driver);
848 }
849 
850 /*
851  * This function is called when the machine starts, resets or due to
852  * S3 resume.
853  */
854 static void tpm_tis_reset(DeviceState *dev)
855 {
856     TPMState *s = TPM(dev);
857     TPMTISEmuState *tis = &s->s.tis;
858     int c;
859 
860     tpm_backend_reset(s->be_driver);
861 
862     tis->active_locty = TPM_TIS_NO_LOCALITY;
863     tis->next_locty = TPM_TIS_NO_LOCALITY;
864     tis->aborting_locty = TPM_TIS_NO_LOCALITY;
865 
866     for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
867         tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
868         tis->loc[c].sts = 0;
869         tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
870         tis->loc[c].ints = 0;
871         tis->loc[c].state = TPM_TIS_STATE_IDLE;
872 
873         tis->loc[c].w_offset = 0;
874         tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer);
875         tis->loc[c].r_offset = 0;
876         tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer);
877     }
878 
879     tpm_tis_do_startup_tpm(s);
880 }
881 
882 static const VMStateDescription vmstate_tpm_tis = {
883     .name = "tpm",
884     .unmigratable = 1,
885 };
886 
887 static Property tpm_tis_properties[] = {
888     DEFINE_PROP_UINT32("irq", TPMState,
889                        s.tis.irq_num, TPM_TIS_IRQ),
890     DEFINE_PROP_STRING("tpmdev", TPMState, backend),
891     DEFINE_PROP_END_OF_LIST(),
892 };
893 
894 static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
895 {
896     TPMState *s = TPM(dev);
897     TPMTISEmuState *tis = &s->s.tis;
898 
899     s->be_driver = qemu_find_tpm(s->backend);
900     if (!s->be_driver) {
901         error_setg(errp, "tpm_tis: backend driver with id %s could not be "
902                    "found", s->backend);
903         return;
904     }
905 
906     s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
907 
908     if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
909         error_setg(errp, "tpm_tis: backend driver with id %s could not be "
910                    "initialized", s->backend);
911         return;
912     }
913 
914     if (tis->irq_num > 15) {
915         error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
916                    "of 0 to 15.\n", tis->irq_num);
917         return;
918     }
919 
920     tis->bh = qemu_bh_new(tpm_tis_receive_bh, s);
921 
922     isa_init_irq(&s->busdev, &tis->irq, tis->irq_num);
923 }
924 
925 static void tpm_tis_initfn(Object *obj)
926 {
927     ISADevice *dev = ISA_DEVICE(obj);
928     TPMState *s = TPM(obj);
929 
930     memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
931                           s, "tpm-tis-mmio",
932                           TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
933     memory_region_add_subregion(isa_address_space(dev), TPM_TIS_ADDR_BASE,
934                                 &s->mmio);
935 }
936 
937 static void tpm_tis_class_init(ObjectClass *klass, void *data)
938 {
939     DeviceClass *dc = DEVICE_CLASS(klass);
940 
941     dc->realize = tpm_tis_realizefn;
942     dc->props = tpm_tis_properties;
943     dc->reset = tpm_tis_reset;
944     dc->vmsd  = &vmstate_tpm_tis;
945 }
946 
947 static const TypeInfo tpm_tis_info = {
948     .name = TYPE_TPM_TIS,
949     .parent = TYPE_ISA_DEVICE,
950     .instance_size = sizeof(TPMState),
951     .instance_init = tpm_tis_initfn,
952     .class_init  = tpm_tis_class_init,
953 };
954 
955 static void tpm_tis_register(void)
956 {
957     type_register_static(&tpm_tis_info);
958     tpm_register_model(TPM_MODEL_TPM_TIS);
959 }
960 
961 type_init(tpm_tis_register)
962