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