]> Git Repo - qemu.git/blob - hw/tpm/tpm_tis.c
hw: Fix qemu_allocate_irqs() leaks
[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 <[email protected]>
8  *  David Safford <[email protected]>
9  *
10  * Xen 4 support: Andrease Niederl <[email protected]>
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 "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 #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
431     if (tpm_backend_had_startup_error(s->be_driver)) {
432         return val;
433     }
434
435     switch (offset) {
436     case TPM_TIS_REG_ACCESS:
437         /* never show the SEIZE flag even though we use it internally */
438         val = tis->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
439         /* the pending flag is always calculated */
440         if (tpm_tis_check_request_use_except(s, locty)) {
441             val |= TPM_TIS_ACCESS_PENDING_REQUEST;
442         }
443         val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
444         break;
445     case TPM_TIS_REG_INT_ENABLE:
446         val = tis->loc[locty].inte;
447         break;
448     case TPM_TIS_REG_INT_VECTOR:
449         val = tis->irq_num;
450         break;
451     case TPM_TIS_REG_INT_STATUS:
452         val = tis->loc[locty].ints;
453         break;
454     case TPM_TIS_REG_INTF_CAPABILITY:
455         val = TPM_TIS_CAPABILITIES_SUPPORTED;
456         break;
457     case TPM_TIS_REG_STS:
458         if (tis->active_locty == locty) {
459             if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
460                 val = TPM_TIS_BURST_COUNT(
461                        tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer)
462                        - tis->loc[locty].r_offset) | tis->loc[locty].sts;
463             } else {
464                 avail = tis->loc[locty].w_buffer.size
465                         - tis->loc[locty].w_offset;
466                 /*
467                  * byte-sized reads should not return 0x00 for 0x100
468                  * available bytes.
469                  */
470                 if (size == 1 && avail > 0xff) {
471                     avail = 0xff;
472                 }
473                 val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts;
474             }
475         }
476         break;
477     case TPM_TIS_REG_DATA_FIFO:
478         if (tis->active_locty == locty) {
479             switch (tis->loc[locty].state) {
480             case TPM_TIS_STATE_COMPLETION:
481                 val = tpm_tis_data_read(s, locty);
482                 break;
483             default:
484                 val = TPM_TIS_NO_DATA_BYTE;
485                 break;
486             }
487         }
488         break;
489     case TPM_TIS_REG_DID_VID:
490         val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
491         break;
492     case TPM_TIS_REG_RID:
493         val = TPM_TIS_TPM_RID;
494         break;
495 #ifdef DEBUG_TIS
496     case TPM_TIS_REG_DEBUG:
497         tpm_tis_dump_state(opaque, addr);
498         break;
499 #endif
500     }
501
502     if (shift) {
503         val >>= shift;
504     }
505
506     DPRINTF("tpm_tis:  read.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
507
508     return val;
509 }
510
511 /*
512  * Write a value to a register of the TIS interface
513  * See specs pages 33-63 for description of the registers
514  */
515 static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
516                                       uint64_t val, unsigned size,
517                                       bool hw_access)
518 {
519     TPMState *s = opaque;
520     TPMTISEmuState *tis = &s->s.tis;
521     uint16_t off = addr & 0xfff;
522     uint8_t locty = tpm_tis_locality_from_addr(addr);
523     uint8_t active_locty, l;
524     int c, set_new_locty = 1;
525     uint16_t len;
526
527     DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
528
529     if (locty == 4 && !hw_access) {
530         DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
531         return;
532     }
533
534     if (tpm_backend_had_startup_error(s->be_driver)) {
535         return;
536     }
537
538     switch (off) {
539     case TPM_TIS_REG_ACCESS:
540
541         if ((val & TPM_TIS_ACCESS_SEIZE)) {
542             val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
543                      TPM_TIS_ACCESS_ACTIVE_LOCALITY);
544         }
545
546         active_locty = tis->active_locty;
547
548         if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
549             /* give up locality if currently owned */
550             if (tis->active_locty == locty) {
551                 DPRINTF("tpm_tis: Releasing locality %d\n", locty);
552
553                 uint8_t newlocty = TPM_TIS_NO_LOCALITY;
554                 /* anybody wants the locality ? */
555                 for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
556                     if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
557                         DPRINTF("tpm_tis: Locality %d requests use.\n", c);
558                         newlocty = c;
559                         break;
560                     }
561                 }
562                 DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
563                         "Next active locality: %d\n",
564                         newlocty);
565
566                 if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
567                     set_new_locty = 0;
568                     tpm_tis_prep_abort(s, locty, newlocty);
569                 } else {
570                     active_locty = TPM_TIS_NO_LOCALITY;
571                 }
572             } else {
573                 /* not currently the owner; clear a pending request */
574                 tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
575             }
576         }
577
578         if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
579             tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
580         }
581
582         if ((val & TPM_TIS_ACCESS_SEIZE)) {
583             /*
584              * allow seize if a locality is active and the requesting
585              * locality is higher than the one that's active
586              * OR
587              * allow seize for requesting locality if no locality is
588              * active
589              */
590             while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&
591                     locty > tis->active_locty) ||
592                     !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
593                 bool higher_seize = FALSE;
594
595                 /* already a pending SEIZE ? */
596                 if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
597                     break;
598                 }
599
600                 /* check for ongoing seize by a higher locality */
601                 for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
602                     if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
603                         higher_seize = TRUE;
604                         break;
605                     }
606                 }
607
608                 if (higher_seize) {
609                     break;
610                 }
611
612                 /* cancel any seize by a lower locality */
613                 for (l = 0; l < locty - 1; l++) {
614                     tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
615                 }
616
617                 tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
618                 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
619                         "Locality %d seized from locality %d\n",
620                         locty, tis->active_locty);
621                 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");
622                 set_new_locty = 0;
623                 tpm_tis_prep_abort(s, tis->active_locty, locty);
624                 break;
625             }
626         }
627
628         if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
629             if (tis->active_locty != locty) {
630                 if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
631                     tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
632                 } else {
633                     /* no locality active -> make this one active now */
634                     active_locty = locty;
635                 }
636             }
637         }
638
639         if (set_new_locty) {
640             tpm_tis_new_active_locality(s, active_locty);
641         }
642
643         break;
644     case TPM_TIS_REG_INT_ENABLE:
645         if (tis->active_locty != locty) {
646             break;
647         }
648
649         tis->loc[locty].inte = (val & (TPM_TIS_INT_ENABLED |
650                                        TPM_TIS_INT_POLARITY_MASK |
651                                        TPM_TIS_INTERRUPTS_SUPPORTED));
652         break;
653     case TPM_TIS_REG_INT_VECTOR:
654         /* hard wired -- ignore */
655         break;
656     case TPM_TIS_REG_INT_STATUS:
657         if (tis->active_locty != locty) {
658             break;
659         }
660
661         /* clearing of interrupt flags */
662         if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
663             (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
664             tis->loc[locty].ints &= ~val;
665             if (tis->loc[locty].ints == 0) {
666                 qemu_irq_lower(tis->irq);
667                 DPRINTF("tpm_tis: Lowering IRQ\n");
668             }
669         }
670         tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
671         break;
672     case TPM_TIS_REG_STS:
673         if (tis->active_locty != locty) {
674             break;
675         }
676
677         val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
678                 TPM_TIS_STS_RESPONSE_RETRY);
679
680         if (val == TPM_TIS_STS_COMMAND_READY) {
681             switch (tis->loc[locty].state) {
682
683             case TPM_TIS_STATE_READY:
684                 tis->loc[locty].w_offset = 0;
685                 tis->loc[locty].r_offset = 0;
686             break;
687
688             case TPM_TIS_STATE_IDLE:
689                 tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;
690                 tis->loc[locty].state = TPM_TIS_STATE_READY;
691                 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
692             break;
693
694             case TPM_TIS_STATE_EXECUTION:
695             case TPM_TIS_STATE_RECEPTION:
696                 /* abort currently running command */
697                 DPRINTF("tpm_tis: %s: Initiating abort.\n",
698                         __func__);
699                 tpm_tis_prep_abort(s, locty, locty);
700             break;
701
702             case TPM_TIS_STATE_COMPLETION:
703                 tis->loc[locty].w_offset = 0;
704                 tis->loc[locty].r_offset = 0;
705                 /* shortcut to ready state with C/R set */
706                 tis->loc[locty].state = TPM_TIS_STATE_READY;
707                 if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
708                     tis->loc[locty].sts   = TPM_TIS_STS_COMMAND_READY;
709                     tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
710                 }
711                 tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
712             break;
713
714             }
715         } else if (val == TPM_TIS_STS_TPM_GO) {
716             switch (tis->loc[locty].state) {
717             case TPM_TIS_STATE_RECEPTION:
718                 if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
719                     tpm_tis_tpm_send(s, locty);
720                 }
721                 break;
722             default:
723                 /* ignore */
724                 break;
725             }
726         } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
727             switch (tis->loc[locty].state) {
728             case TPM_TIS_STATE_COMPLETION:
729                 tis->loc[locty].r_offset = 0;
730                 tis->loc[locty].sts = TPM_TIS_STS_VALID |
731                                       TPM_TIS_STS_DATA_AVAILABLE;
732                 break;
733             default:
734                 /* ignore */
735                 break;
736             }
737         }
738         break;
739     case TPM_TIS_REG_DATA_FIFO:
740         /* data fifo */
741         if (tis->active_locty != locty) {
742             break;
743         }
744
745         if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||
746             tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
747             tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
748             /* drop the byte */
749         } else {
750             DPRINTF("tpm_tis: Byte to send to TPM: %02x\n", (uint8_t)val);
751             if (tis->loc[locty].state == TPM_TIS_STATE_READY) {
752                 tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;
753                 tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID;
754             }
755
756             if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
757                 if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {
758                     tis->loc[locty].w_buffer.
759                         buffer[tis->loc[locty].w_offset++] = (uint8_t)val;
760                 } else {
761                     tis->loc[locty].sts = TPM_TIS_STS_VALID;
762                 }
763             }
764
765             /* check for complete packet */
766             if (tis->loc[locty].w_offset > 5 &&
767                 (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
768                 /* we have a packet length - see if we have all of it */
769 #ifdef RAISE_STS_IRQ
770                 bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);
771 #endif
772                 len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
773                 if (len > tis->loc[locty].w_offset) {
774                     tis->loc[locty].sts = TPM_TIS_STS_EXPECT |
775                                           TPM_TIS_STS_VALID;
776                 } else {
777                     /* packet complete */
778                     tis->loc[locty].sts = TPM_TIS_STS_VALID;
779                 }
780 #ifdef RAISE_STS_IRQ
781                 if (needIrq) {
782                     tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
783                 }
784 #endif
785             }
786         }
787         break;
788     }
789 }
790
791 static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
792                                uint64_t val, unsigned size)
793 {
794     return tpm_tis_mmio_write_intern(opaque, addr, val, size, false);
795 }
796
797 static const MemoryRegionOps tpm_tis_memory_ops = {
798     .read = tpm_tis_mmio_read,
799     .write = tpm_tis_mmio_write,
800     .endianness = DEVICE_LITTLE_ENDIAN,
801     .valid = {
802         .min_access_size = 1,
803         .max_access_size = 4,
804     },
805 };
806
807 static int tpm_tis_do_startup_tpm(TPMState *s)
808 {
809     return tpm_backend_startup_tpm(s->be_driver);
810 }
811
812 /*
813  * This function is called when the machine starts, resets or due to
814  * S3 resume.
815  */
816 static void tpm_tis_reset(DeviceState *dev)
817 {
818     TPMState *s = TPM(dev);
819     TPMTISEmuState *tis = &s->s.tis;
820     int c;
821
822     tpm_backend_reset(s->be_driver);
823
824     tis->active_locty = TPM_TIS_NO_LOCALITY;
825     tis->next_locty = TPM_TIS_NO_LOCALITY;
826     tis->aborting_locty = TPM_TIS_NO_LOCALITY;
827
828     for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
829         tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
830         tis->loc[c].sts = 0;
831         tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
832         tis->loc[c].ints = 0;
833         tis->loc[c].state = TPM_TIS_STATE_IDLE;
834
835         tis->loc[c].w_offset = 0;
836         tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer);
837         tis->loc[c].r_offset = 0;
838         tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer);
839     }
840
841     tpm_tis_do_startup_tpm(s);
842 }
843
844 static const VMStateDescription vmstate_tpm_tis = {
845     .name = "tpm",
846     .unmigratable = 1,
847 };
848
849 static Property tpm_tis_properties[] = {
850     DEFINE_PROP_UINT32("irq", TPMState,
851                        s.tis.irq_num, TPM_TIS_IRQ),
852     DEFINE_PROP_STRING("tpmdev", TPMState, backend),
853     DEFINE_PROP_END_OF_LIST(),
854 };
855
856 static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
857 {
858     TPMState *s = TPM(dev);
859     TPMTISEmuState *tis = &s->s.tis;
860
861     s->be_driver = qemu_find_tpm(s->backend);
862     if (!s->be_driver) {
863         error_setg(errp, "tpm_tis: backend driver with id %s could not be "
864                    "found", s->backend);
865         return;
866     }
867
868     s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
869
870     if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
871         error_setg(errp, "tpm_tis: backend driver with id %s could not be "
872                    "initialized", s->backend);
873         return;
874     }
875
876     if (tis->irq_num > 15) {
877         error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
878                    "of 0 to 15.\n", tis->irq_num);
879         return;
880     }
881
882     tis->bh = qemu_bh_new(tpm_tis_receive_bh, s);
883
884     isa_init_irq(&s->busdev, &tis->irq, tis->irq_num);
885 }
886
887 static void tpm_tis_initfn(Object *obj)
888 {
889     ISADevice *dev = ISA_DEVICE(obj);
890     TPMState *s = TPM(obj);
891
892     memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
893                           s, "tpm-tis-mmio",
894                           TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
895     memory_region_add_subregion(isa_address_space(dev), TPM_TIS_ADDR_BASE,
896                                 &s->mmio);
897 }
898
899 static void tpm_tis_uninitfn(Object *obj)
900 {
901     TPMState *s = TPM(obj);
902
903     memory_region_del_subregion(get_system_memory(), &s->mmio);
904     memory_region_destroy(&s->mmio);
905 }
906
907 static void tpm_tis_class_init(ObjectClass *klass, void *data)
908 {
909     DeviceClass *dc = DEVICE_CLASS(klass);
910
911     dc->realize = tpm_tis_realizefn;
912     dc->props = tpm_tis_properties;
913     dc->reset = tpm_tis_reset;
914     dc->vmsd  = &vmstate_tpm_tis;
915 }
916
917 static const TypeInfo tpm_tis_info = {
918     .name = TYPE_TPM_TIS,
919     .parent = TYPE_ISA_DEVICE,
920     .instance_size = sizeof(TPMState),
921     .instance_init = tpm_tis_initfn,
922     .instance_finalize = tpm_tis_uninitfn,
923     .class_init  = tpm_tis_class_init,
924 };
925
926 static void tpm_tis_register(void)
927 {
928     type_register_static(&tpm_tis_info);
929     tpm_register_model(TPM_MODEL_TPM_TIS);
930 }
931
932 type_init(tpm_tis_register)
This page took 0.077804 seconds and 4 git commands to generate.