target-ppc: Use QOM method dispatch for MMU fault handling
[qemu/agraf.git] / tpm / tpm_tis.c
blobe93825eec15cb154539c1157651c7c6fc1fd625f
1 /*
2 * tpm_tis.c - QEMU's TPM TIS interface emulator
4 * Copyright (C) 2006,2010-2013 IBM Corporation
6 * Authors:
7 * Stefan Berger <stefanb@us.ibm.com>
8 * David Safford <safford@us.ibm.com>
10 * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
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.
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.
22 #include "tpm_int.h"
23 #include "block/block.h"
24 #include "exec/address-spaces.h"
25 #include "hw/hw.h"
26 #include "hw/pc.h"
27 #include "hw/pci/pci_ids.h"
28 #include "tpm/tpm_tis.h"
29 #include "qemu-common.h"
31 /*#define DEBUG_TIS */
33 #ifdef DEBUG_TIS
34 #define DPRINTF(fmt, ...) \
35 do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
36 #else
37 #define DPRINTF(fmt, ...) \
38 do { } while (0)
39 #endif
41 /* whether the STS interrupt is supported */
42 #define RAISE_STS_IRQ
44 /* tis registers */
45 #define TPM_TIS_REG_ACCESS 0x00
46 #define TPM_TIS_REG_INT_ENABLE 0x08
47 #define TPM_TIS_REG_INT_VECTOR 0x0c
48 #define TPM_TIS_REG_INT_STATUS 0x10
49 #define TPM_TIS_REG_INTF_CAPABILITY 0x14
50 #define TPM_TIS_REG_STS 0x18
51 #define TPM_TIS_REG_DATA_FIFO 0x24
52 #define TPM_TIS_REG_DID_VID 0xf00
53 #define TPM_TIS_REG_RID 0xf04
55 /* vendor-specific registers */
56 #define TPM_TIS_REG_DEBUG 0xf90
58 #define TPM_TIS_STS_VALID (1 << 7)
59 #define TPM_TIS_STS_COMMAND_READY (1 << 6)
60 #define TPM_TIS_STS_TPM_GO (1 << 5)
61 #define TPM_TIS_STS_DATA_AVAILABLE (1 << 4)
62 #define TPM_TIS_STS_EXPECT (1 << 3)
63 #define TPM_TIS_STS_RESPONSE_RETRY (1 << 1)
65 #define TPM_TIS_BURST_COUNT_SHIFT 8
66 #define TPM_TIS_BURST_COUNT(X) \
67 ((X) << TPM_TIS_BURST_COUNT_SHIFT)
69 #define TPM_TIS_ACCESS_TPM_REG_VALID_STS (1 << 7)
70 #define TPM_TIS_ACCESS_ACTIVE_LOCALITY (1 << 5)
71 #define TPM_TIS_ACCESS_BEEN_SEIZED (1 << 4)
72 #define TPM_TIS_ACCESS_SEIZE (1 << 3)
73 #define TPM_TIS_ACCESS_PENDING_REQUEST (1 << 2)
74 #define TPM_TIS_ACCESS_REQUEST_USE (1 << 1)
75 #define TPM_TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0)
77 #define TPM_TIS_INT_ENABLED (1 << 31)
78 #define TPM_TIS_INT_DATA_AVAILABLE (1 << 0)
79 #define TPM_TIS_INT_STS_VALID (1 << 1)
80 #define TPM_TIS_INT_LOCALITY_CHANGED (1 << 2)
81 #define TPM_TIS_INT_COMMAND_READY (1 << 7)
83 #define TPM_TIS_INT_POLARITY_MASK (3 << 3)
84 #define TPM_TIS_INT_POLARITY_LOW_LEVEL (1 << 3)
86 #ifndef RAISE_STS_IRQ
88 #define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
89 TPM_TIS_INT_DATA_AVAILABLE | \
90 TPM_TIS_INT_COMMAND_READY)
92 #else
94 #define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
95 TPM_TIS_INT_DATA_AVAILABLE | \
96 TPM_TIS_INT_STS_VALID | \
97 TPM_TIS_INT_COMMAND_READY)
99 #endif
101 #define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */
102 #define TPM_TIS_CAPABILITIES_SUPPORTED (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
103 TPM_TIS_INTERRUPTS_SUPPORTED)
105 #define TPM_TIS_TPM_DID 0x0001
106 #define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM
107 #define TPM_TIS_TPM_RID 0x0001
109 #define TPM_TIS_NO_DATA_BYTE 0xff
111 /* local prototypes */
113 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
114 unsigned size);
116 /* utility functions */
118 static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
120 return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
123 static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
125 return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
128 static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
130 #ifdef DEBUG_TIS
131 uint32_t len, i;
133 len = tpm_tis_get_size_from_buffer(sb);
134 DPRINTF("tpm_tis: %s length = %d\n", string, len);
135 for (i = 0; i < len; i++) {
136 if (i && !(i % 16)) {
137 DPRINTF("\n");
139 DPRINTF("%.2X ", sb->buffer[i]);
141 DPRINTF("\n");
142 #endif
146 * Send a request to the TPM.
148 static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
150 TPMTISEmuState *tis = &s->s.tis;
152 tpm_tis_show_buffer(&tis->loc[locty].w_buffer, "tpm_tis: To TPM");
154 s->locty_number = locty;
155 s->locty_data = &tis->loc[locty];
158 * w_offset serves as length indicator for length of data;
159 * it's reset when the response comes back
161 tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
163 s->be_driver->ops->deliver_request(s->be_driver);
166 /* raise an interrupt if allowed */
167 static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
169 TPMTISEmuState *tis = &s->s.tis;
171 if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
172 return;
175 if ((tis->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
176 (tis->loc[locty].inte & irqmask)) {
177 DPRINTF("tpm_tis: Raising IRQ for flag %08x\n", irqmask);
178 qemu_irq_raise(s->s.tis.irq);
179 tis->loc[locty].ints |= irqmask;
183 static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
185 uint8_t l;
187 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
188 if (l == locty) {
189 continue;
191 if ((s->s.tis.loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
192 return 1;
196 return 0;
199 static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
201 TPMTISEmuState *tis = &s->s.tis;
202 bool change = (s->s.tis.active_locty != new_active_locty);
203 bool is_seize;
204 uint8_t mask;
206 if (change && TPM_TIS_IS_VALID_LOCTY(s->s.tis.active_locty)) {
207 is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
208 tis->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
210 if (is_seize) {
211 mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
212 } else {
213 mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
214 TPM_TIS_ACCESS_REQUEST_USE);
216 /* reset flags on the old active locality */
217 tis->loc[s->s.tis.active_locty].access &= mask;
219 if (is_seize) {
220 tis->loc[tis->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
224 tis->active_locty = new_active_locty;
226 DPRINTF("tpm_tis: Active locality is now %d\n", s->s.tis.active_locty);
228 if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
229 /* set flags on the new active locality */
230 tis->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
231 tis->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
232 TPM_TIS_ACCESS_SEIZE);
235 if (change) {
236 tpm_tis_raise_irq(s, tis->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
240 /* abort -- this function switches the locality */
241 static void tpm_tis_abort(TPMState *s, uint8_t locty)
243 TPMTISEmuState *tis = &s->s.tis;
245 tis->loc[locty].r_offset = 0;
246 tis->loc[locty].w_offset = 0;
248 DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis->next_locty);
251 * Need to react differently depending on who's aborting now and
252 * which locality will become active afterwards.
254 if (tis->aborting_locty == tis->next_locty) {
255 tis->loc[tis->aborting_locty].state = TPM_TIS_STATE_READY;
256 tis->loc[tis->aborting_locty].sts = TPM_TIS_STS_COMMAND_READY;
257 tpm_tis_raise_irq(s, tis->aborting_locty, TPM_TIS_INT_COMMAND_READY);
260 /* locality after abort is another one than the current one */
261 tpm_tis_new_active_locality(s, tis->next_locty);
263 tis->next_locty = TPM_TIS_NO_LOCALITY;
264 /* nobody's aborting a command anymore */
265 tis->aborting_locty = TPM_TIS_NO_LOCALITY;
268 /* prepare aborting current command */
269 static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
271 TPMTISEmuState *tis = &s->s.tis;
272 uint8_t busy_locty;
274 tis->aborting_locty = locty;
275 tis->next_locty = newlocty; /* locality after successful abort */
278 * only abort a command using an interrupt if currently executing
279 * a command AND if there's a valid connection to the vTPM.
281 for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
282 if (tis->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
284 * request the backend to cancel. Some backends may not
285 * support it
287 s->be_driver->ops->cancel_cmd(s->be_driver);
288 return;
292 tpm_tis_abort(s, locty);
295 static void tpm_tis_receive_bh(void *opaque)
297 TPMState *s = opaque;
298 TPMTISEmuState *tis = &s->s.tis;
299 uint8_t locty = s->locty_number;
301 tis->loc[locty].sts = TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE;
302 tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
303 tis->loc[locty].r_offset = 0;
304 tis->loc[locty].w_offset = 0;
306 if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) {
307 tpm_tis_abort(s, locty);
310 #ifndef RAISE_STS_IRQ
311 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_DATA_AVAILABLE);
312 #else
313 tpm_tis_raise_irq(s, locty,
314 TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
315 #endif
319 * Callback from the TPM to indicate that the response was received.
321 static void tpm_tis_receive_cb(TPMState *s, uint8_t locty)
323 TPMTISEmuState *tis = &s->s.tis;
325 assert(s->locty_number == locty);
327 qemu_bh_schedule(tis->bh);
331 * Read a byte of response data
333 static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
335 TPMTISEmuState *tis = &s->s.tis;
336 uint32_t ret = TPM_TIS_NO_DATA_BYTE;
337 uint16_t len;
339 if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
340 len = tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
342 ret = tis->loc[locty].r_buffer.buffer[tis->loc[locty].r_offset++];
343 if (tis->loc[locty].r_offset >= len) {
344 /* got last byte */
345 tis->loc[locty].sts = TPM_TIS_STS_VALID;
346 #ifdef RAISE_STS_IRQ
347 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
348 #endif
350 DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x [%d]\n",
351 ret, tis->loc[locty].r_offset-1);
354 return ret;
357 #ifdef DEBUG_TIS
358 static void tpm_tis_dump_state(void *opaque, hwaddr addr)
360 static const unsigned regs[] = {
361 TPM_TIS_REG_ACCESS,
362 TPM_TIS_REG_INT_ENABLE,
363 TPM_TIS_REG_INT_VECTOR,
364 TPM_TIS_REG_INT_STATUS,
365 TPM_TIS_REG_INTF_CAPABILITY,
366 TPM_TIS_REG_STS,
367 TPM_TIS_REG_DID_VID,
368 TPM_TIS_REG_RID,
369 0xfff};
370 int idx;
371 uint8_t locty = tpm_tis_locality_from_addr(addr);
372 hwaddr base = addr & ~0xfff;
373 TPMState *s = opaque;
374 TPMTISEmuState *tis = &s->s.tis;
376 DPRINTF("tpm_tis: active locality : %d\n"
377 "tpm_tis: state of locality %d : %d\n"
378 "tpm_tis: register dump:\n",
379 tis->active_locty,
380 locty, tis->loc[locty].state);
382 for (idx = 0; regs[idx] != 0xfff; idx++) {
383 DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
384 (uint32_t)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
387 DPRINTF("tpm_tis: read offset : %d\n"
388 "tpm_tis: result buffer : ",
389 tis->loc[locty].r_offset);
390 for (idx = 0;
391 idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
392 idx++) {
393 DPRINTF("%c%02x%s",
394 tis->loc[locty].r_offset == idx ? '>' : ' ',
395 tis->loc[locty].r_buffer.buffer[idx],
396 ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
398 DPRINTF("\n"
399 "tpm_tis: write offset : %d\n"
400 "tpm_tis: request buffer: ",
401 tis->loc[locty].w_offset);
402 for (idx = 0;
403 idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
404 idx++) {
405 DPRINTF("%c%02x%s",
406 tis->loc[locty].w_offset == idx ? '>' : ' ',
407 tis->loc[locty].w_buffer.buffer[idx],
408 ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
410 DPRINTF("\n");
412 #endif
415 * Read a register of the TIS interface
416 * See specs pages 33-63 for description of the registers
418 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
419 unsigned size)
421 TPMState *s = opaque;
422 TPMTISEmuState *tis = &s->s.tis;
423 uint16_t offset = addr & 0xffc;
424 uint8_t shift = (addr & 0x3) * 8;
425 uint32_t val = 0xffffffff;
426 uint8_t locty = tpm_tis_locality_from_addr(addr);
427 uint32_t avail;
429 if (s->be_driver->ops->had_startup_error(s->be_driver)) {
430 return val;
433 switch (offset) {
434 case TPM_TIS_REG_ACCESS:
435 /* never show the SEIZE flag even though we use it internally */
436 val = tis->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
437 /* the pending flag is always calculated */
438 if (tpm_tis_check_request_use_except(s, locty)) {
439 val |= TPM_TIS_ACCESS_PENDING_REQUEST;
441 val |= !s->be_driver->ops->get_tpm_established_flag(s->be_driver);
442 break;
443 case TPM_TIS_REG_INT_ENABLE:
444 val = tis->loc[locty].inte;
445 break;
446 case TPM_TIS_REG_INT_VECTOR:
447 val = tis->irq_num;
448 break;
449 case TPM_TIS_REG_INT_STATUS:
450 val = tis->loc[locty].ints;
451 break;
452 case TPM_TIS_REG_INTF_CAPABILITY:
453 val = TPM_TIS_CAPABILITIES_SUPPORTED;
454 break;
455 case TPM_TIS_REG_STS:
456 if (tis->active_locty == locty) {
457 if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
458 val = TPM_TIS_BURST_COUNT(
459 tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer)
460 - tis->loc[locty].r_offset) | tis->loc[locty].sts;
461 } else {
462 avail = tis->loc[locty].w_buffer.size
463 - tis->loc[locty].w_offset;
465 * byte-sized reads should not return 0x00 for 0x100
466 * available bytes.
468 if (size == 1 && avail > 0xff) {
469 avail = 0xff;
471 val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts;
474 break;
475 case TPM_TIS_REG_DATA_FIFO:
476 if (tis->active_locty == locty) {
477 switch (tis->loc[locty].state) {
478 case TPM_TIS_STATE_COMPLETION:
479 val = tpm_tis_data_read(s, locty);
480 break;
481 default:
482 val = TPM_TIS_NO_DATA_BYTE;
483 break;
486 break;
487 case TPM_TIS_REG_DID_VID:
488 val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
489 break;
490 case TPM_TIS_REG_RID:
491 val = TPM_TIS_TPM_RID;
492 break;
493 #ifdef DEBUG_TIS
494 case TPM_TIS_REG_DEBUG:
495 tpm_tis_dump_state(opaque, addr);
496 break;
497 #endif
500 if (shift) {
501 val >>= shift;
504 DPRINTF("tpm_tis: read.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
506 return val;
510 * Write a value to a register of the TIS interface
511 * See specs pages 33-63 for description of the registers
513 static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
514 uint64_t val, unsigned size,
515 bool hw_access)
517 TPMState *s = opaque;
518 TPMTISEmuState *tis = &s->s.tis;
519 uint16_t off = addr & 0xfff;
520 uint8_t locty = tpm_tis_locality_from_addr(addr);
521 uint8_t active_locty, l;
522 int c, set_new_locty = 1;
523 uint16_t len;
525 DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
527 if (locty == 4 && !hw_access) {
528 DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
529 return;
532 if (s->be_driver->ops->had_startup_error(s->be_driver)) {
533 return;
536 switch (off) {
537 case TPM_TIS_REG_ACCESS:
539 if ((val & TPM_TIS_ACCESS_SEIZE)) {
540 val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
541 TPM_TIS_ACCESS_ACTIVE_LOCALITY);
544 active_locty = tis->active_locty;
546 if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
547 /* give up locality if currently owned */
548 if (tis->active_locty == locty) {
549 DPRINTF("tpm_tis: Releasing locality %d\n", locty);
551 uint8_t newlocty = TPM_TIS_NO_LOCALITY;
552 /* anybody wants the locality ? */
553 for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
554 if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
555 DPRINTF("tpm_tis: Locality %d requests use.\n", c);
556 newlocty = c;
557 break;
560 DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
561 "Next active locality: %d\n",
562 newlocty);
564 if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
565 set_new_locty = 0;
566 tpm_tis_prep_abort(s, locty, newlocty);
567 } else {
568 active_locty = TPM_TIS_NO_LOCALITY;
570 } else {
571 /* not currently the owner; clear a pending request */
572 tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
576 if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
577 tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
580 if ((val & TPM_TIS_ACCESS_SEIZE)) {
582 * allow seize if a locality is active and the requesting
583 * locality is higher than the one that's active
584 * OR
585 * allow seize for requesting locality if no locality is
586 * active
588 while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&
589 locty > tis->active_locty) ||
590 !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
591 bool higher_seize = FALSE;
593 /* already a pending SEIZE ? */
594 if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
595 break;
598 /* check for ongoing seize by a higher locality */
599 for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
600 if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
601 higher_seize = TRUE;
602 break;
606 if (higher_seize) {
607 break;
610 /* cancel any seize by a lower locality */
611 for (l = 0; l < locty - 1; l++) {
612 tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
615 tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
616 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
617 "Locality %d seized from locality %d\n",
618 locty, tis->active_locty);
619 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");
620 set_new_locty = 0;
621 tpm_tis_prep_abort(s, tis->active_locty, locty);
622 break;
626 if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
627 if (tis->active_locty != locty) {
628 if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
629 tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
630 } else {
631 /* no locality active -> make this one active now */
632 active_locty = locty;
637 if (set_new_locty) {
638 tpm_tis_new_active_locality(s, active_locty);
641 break;
642 case TPM_TIS_REG_INT_ENABLE:
643 if (tis->active_locty != locty) {
644 break;
647 tis->loc[locty].inte = (val & (TPM_TIS_INT_ENABLED |
648 TPM_TIS_INT_POLARITY_MASK |
649 TPM_TIS_INTERRUPTS_SUPPORTED));
650 break;
651 case TPM_TIS_REG_INT_VECTOR:
652 /* hard wired -- ignore */
653 break;
654 case TPM_TIS_REG_INT_STATUS:
655 if (tis->active_locty != locty) {
656 break;
659 /* clearing of interrupt flags */
660 if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
661 (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
662 tis->loc[locty].ints &= ~val;
663 if (tis->loc[locty].ints == 0) {
664 qemu_irq_lower(tis->irq);
665 DPRINTF("tpm_tis: Lowering IRQ\n");
668 tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
669 break;
670 case TPM_TIS_REG_STS:
671 if (tis->active_locty != locty) {
672 break;
675 val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
676 TPM_TIS_STS_RESPONSE_RETRY);
678 if (val == TPM_TIS_STS_COMMAND_READY) {
679 switch (tis->loc[locty].state) {
681 case TPM_TIS_STATE_READY:
682 tis->loc[locty].w_offset = 0;
683 tis->loc[locty].r_offset = 0;
684 break;
686 case TPM_TIS_STATE_IDLE:
687 tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;
688 tis->loc[locty].state = TPM_TIS_STATE_READY;
689 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
690 break;
692 case TPM_TIS_STATE_EXECUTION:
693 case TPM_TIS_STATE_RECEPTION:
694 /* abort currently running command */
695 DPRINTF("tpm_tis: %s: Initiating abort.\n",
696 __func__);
697 tpm_tis_prep_abort(s, locty, locty);
698 break;
700 case TPM_TIS_STATE_COMPLETION:
701 tis->loc[locty].w_offset = 0;
702 tis->loc[locty].r_offset = 0;
703 /* shortcut to ready state with C/R set */
704 tis->loc[locty].state = TPM_TIS_STATE_READY;
705 if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
706 tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;
707 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
709 tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
710 break;
713 } else if (val == TPM_TIS_STS_TPM_GO) {
714 switch (tis->loc[locty].state) {
715 case TPM_TIS_STATE_RECEPTION:
716 if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
717 tpm_tis_tpm_send(s, locty);
719 break;
720 default:
721 /* ignore */
722 break;
724 } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
725 switch (tis->loc[locty].state) {
726 case TPM_TIS_STATE_COMPLETION:
727 tis->loc[locty].r_offset = 0;
728 tis->loc[locty].sts = TPM_TIS_STS_VALID |
729 TPM_TIS_STS_DATA_AVAILABLE;
730 break;
731 default:
732 /* ignore */
733 break;
736 break;
737 case TPM_TIS_REG_DATA_FIFO:
738 /* data fifo */
739 if (tis->active_locty != locty) {
740 break;
743 if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||
744 tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
745 tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
746 /* drop the byte */
747 } else {
748 DPRINTF("tpm_tis: Byte to send to TPM: %02x\n", (uint8_t)val);
749 if (tis->loc[locty].state == TPM_TIS_STATE_READY) {
750 tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;
751 tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID;
754 if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
755 if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {
756 tis->loc[locty].w_buffer.
757 buffer[tis->loc[locty].w_offset++] = (uint8_t)val;
758 } else {
759 tis->loc[locty].sts = TPM_TIS_STS_VALID;
763 /* check for complete packet */
764 if (tis->loc[locty].w_offset > 5 &&
765 (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
766 /* we have a packet length - see if we have all of it */
767 #ifdef RAISE_STS_IRQ
768 bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);
769 #endif
770 len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
771 if (len > tis->loc[locty].w_offset) {
772 tis->loc[locty].sts = TPM_TIS_STS_EXPECT |
773 TPM_TIS_STS_VALID;
774 } else {
775 /* packet complete */
776 tis->loc[locty].sts = TPM_TIS_STS_VALID;
778 #ifdef RAISE_STS_IRQ
779 if (needIrq) {
780 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
782 #endif
785 break;
789 static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
790 uint64_t val, unsigned size)
792 return tpm_tis_mmio_write_intern(opaque, addr, val, size, false);
795 static const MemoryRegionOps tpm_tis_memory_ops = {
796 .read = tpm_tis_mmio_read,
797 .write = tpm_tis_mmio_write,
798 .endianness = DEVICE_LITTLE_ENDIAN,
799 .valid = {
800 .min_access_size = 1,
801 .max_access_size = 4,
805 static int tpm_tis_do_startup_tpm(TPMState *s)
807 return s->be_driver->ops->startup_tpm(s->be_driver);
811 * This function is called when the machine starts, resets or due to
812 * S3 resume.
814 static void tpm_tis_reset(DeviceState *dev)
816 TPMState *s = TPM(dev);
817 TPMTISEmuState *tis = &s->s.tis;
818 int c;
820 s->be_driver->ops->reset(s->be_driver);
822 tis->active_locty = TPM_TIS_NO_LOCALITY;
823 tis->next_locty = TPM_TIS_NO_LOCALITY;
824 tis->aborting_locty = TPM_TIS_NO_LOCALITY;
826 for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
827 tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
828 tis->loc[c].sts = 0;
829 tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
830 tis->loc[c].ints = 0;
831 tis->loc[c].state = TPM_TIS_STATE_IDLE;
833 tis->loc[c].w_offset = 0;
834 s->be_driver->ops->realloc_buffer(&tis->loc[c].w_buffer);
835 tis->loc[c].r_offset = 0;
836 s->be_driver->ops->realloc_buffer(&tis->loc[c].r_buffer);
839 tpm_tis_do_startup_tpm(s);
842 static const VMStateDescription vmstate_tpm_tis = {
843 .name = "tpm",
844 .unmigratable = 1,
847 static Property tpm_tis_properties[] = {
848 DEFINE_PROP_UINT32("irq", TPMState,
849 s.tis.irq_num, TPM_TIS_IRQ),
850 DEFINE_PROP_STRING("tpmdev", TPMState, backend),
851 DEFINE_PROP_END_OF_LIST(),
854 static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
856 TPMState *s = TPM(dev);
857 TPMTISEmuState *tis = &s->s.tis;
859 s->be_driver = qemu_find_tpm(s->backend);
860 if (!s->be_driver) {
861 error_setg(errp, "tpm_tis: backend driver with id %s could not be "
862 "found", s->backend);
863 return;
866 s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
868 if (s->be_driver->ops->init(s->be_driver, s, tpm_tis_receive_cb)) {
869 error_setg(errp, "tpm_tis: backend driver with id %s could not be "
870 "initialized", s->backend);
871 return;
874 if (tis->irq_num > 15) {
875 error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
876 "of 0 to 15.\n", tis->irq_num);
877 return;
880 tis->bh = qemu_bh_new(tpm_tis_receive_bh, s);
882 isa_init_irq(&s->busdev, &tis->irq, tis->irq_num);
885 static void tpm_tis_initfn(Object *obj)
887 ISADevice *dev = ISA_DEVICE(obj);
888 TPMState *s = TPM(obj);
890 memory_region_init_io(&s->mmio, &tpm_tis_memory_ops, s, "tpm-tis-mmio",
891 TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
892 memory_region_add_subregion(isa_address_space(dev), TPM_TIS_ADDR_BASE,
893 &s->mmio);
896 static void tpm_tis_uninitfn(Object *obj)
898 TPMState *s = TPM(obj);
900 memory_region_del_subregion(get_system_memory(), &s->mmio);
901 memory_region_destroy(&s->mmio);
904 static void tpm_tis_class_init(ObjectClass *klass, void *data)
906 DeviceClass *dc = DEVICE_CLASS(klass);
908 dc->realize = tpm_tis_realizefn;
909 dc->props = tpm_tis_properties;
910 dc->reset = tpm_tis_reset;
911 dc->vmsd = &vmstate_tpm_tis;
914 static const TypeInfo tpm_tis_info = {
915 .name = TYPE_TPM_TIS,
916 .parent = TYPE_ISA_DEVICE,
917 .instance_size = sizeof(TPMState),
918 .instance_init = tpm_tis_initfn,
919 .instance_finalize = tpm_tis_uninitfn,
920 .class_init = tpm_tis_class_init,
923 static void tpm_tis_register(void)
925 type_register_static(&tpm_tis_info);
926 tpm_register_model(TPM_MODEL_TPM_TIS);
929 type_init(tpm_tis_register)