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