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