tpm: Support for XFIFO register
[qemu/ar7.git] / hw / tpm / tpm_tis.c
bloba37c7ce052ced219d4ca64b0787d489b55158f31
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 "sysemu/tpm_backend.h"
23 #include "tpm_int.h"
24 #include "sysemu/block-backend.h"
25 #include "exec/address-spaces.h"
26 #include "hw/hw.h"
27 #include "hw/i386/pc.h"
28 #include "hw/pci/pci_ids.h"
29 #include "tpm_tis.h"
30 #include "qemu-common.h"
31 #include "qemu/main-loop.h"
33 /*#define DEBUG_TIS */
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
43 /* whether the STS interrupt is supported */
44 #define RAISE_STS_IRQ
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_DATA_XFIFO 0x80
55 #define TPM_TIS_REG_DATA_XFIFO_END 0xbc
56 #define TPM_TIS_REG_DID_VID 0xf00
57 #define TPM_TIS_REG_RID 0xf04
59 /* vendor-specific registers */
60 #define TPM_TIS_REG_DEBUG 0xf90
62 #define TPM_TIS_STS_VALID (1 << 7)
63 #define TPM_TIS_STS_COMMAND_READY (1 << 6)
64 #define TPM_TIS_STS_TPM_GO (1 << 5)
65 #define TPM_TIS_STS_DATA_AVAILABLE (1 << 4)
66 #define TPM_TIS_STS_EXPECT (1 << 3)
67 #define TPM_TIS_STS_RESPONSE_RETRY (1 << 1)
69 #define TPM_TIS_BURST_COUNT_SHIFT 8
70 #define TPM_TIS_BURST_COUNT(X) \
71 ((X) << TPM_TIS_BURST_COUNT_SHIFT)
73 #define TPM_TIS_ACCESS_TPM_REG_VALID_STS (1 << 7)
74 #define TPM_TIS_ACCESS_ACTIVE_LOCALITY (1 << 5)
75 #define TPM_TIS_ACCESS_BEEN_SEIZED (1 << 4)
76 #define TPM_TIS_ACCESS_SEIZE (1 << 3)
77 #define TPM_TIS_ACCESS_PENDING_REQUEST (1 << 2)
78 #define TPM_TIS_ACCESS_REQUEST_USE (1 << 1)
79 #define TPM_TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0)
81 #define TPM_TIS_INT_ENABLED (1 << 31)
82 #define TPM_TIS_INT_DATA_AVAILABLE (1 << 0)
83 #define TPM_TIS_INT_STS_VALID (1 << 1)
84 #define TPM_TIS_INT_LOCALITY_CHANGED (1 << 2)
85 #define TPM_TIS_INT_COMMAND_READY (1 << 7)
87 #define TPM_TIS_INT_POLARITY_MASK (3 << 3)
88 #define TPM_TIS_INT_POLARITY_LOW_LEVEL (1 << 3)
90 #ifndef RAISE_STS_IRQ
92 #define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
93 TPM_TIS_INT_DATA_AVAILABLE | \
94 TPM_TIS_INT_COMMAND_READY)
96 #else
98 #define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
99 TPM_TIS_INT_DATA_AVAILABLE | \
100 TPM_TIS_INT_STS_VALID | \
101 TPM_TIS_INT_COMMAND_READY)
103 #endif
105 #define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */
106 #define TPM_TIS_CAPABILITIES_SUPPORTED (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
107 TPM_TIS_INTERRUPTS_SUPPORTED)
109 #define TPM_TIS_TPM_DID 0x0001
110 #define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM
111 #define TPM_TIS_TPM_RID 0x0001
113 #define TPM_TIS_NO_DATA_BYTE 0xff
115 /* local prototypes */
117 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
118 unsigned size);
120 /* utility functions */
122 static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
124 return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
127 static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
129 return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
132 static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
134 #ifdef DEBUG_TIS
135 uint32_t len, i;
137 len = tpm_tis_get_size_from_buffer(sb);
138 DPRINTF("tpm_tis: %s length = %d\n", string, len);
139 for (i = 0; i < len; i++) {
140 if (i && !(i % 16)) {
141 DPRINTF("\n");
143 DPRINTF("%.2X ", sb->buffer[i]);
145 DPRINTF("\n");
146 #endif
150 * Send a request to the TPM.
152 static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
154 TPMTISEmuState *tis = &s->s.tis;
156 tpm_tis_show_buffer(&tis->loc[locty].w_buffer, "tpm_tis: To TPM");
158 s->locty_number = locty;
159 s->locty_data = &tis->loc[locty];
162 * w_offset serves as length indicator for length of data;
163 * it's reset when the response comes back
165 tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
167 tpm_backend_deliver_request(s->be_driver);
170 /* raise an interrupt if allowed */
171 static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
173 TPMTISEmuState *tis = &s->s.tis;
175 if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
176 return;
179 if ((tis->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
180 (tis->loc[locty].inte & irqmask)) {
181 DPRINTF("tpm_tis: Raising IRQ for flag %08x\n", irqmask);
182 qemu_irq_raise(s->s.tis.irq);
183 tis->loc[locty].ints |= irqmask;
187 static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
189 uint8_t l;
191 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
192 if (l == locty) {
193 continue;
195 if ((s->s.tis.loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
196 return 1;
200 return 0;
203 static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
205 TPMTISEmuState *tis = &s->s.tis;
206 bool change = (s->s.tis.active_locty != new_active_locty);
207 bool is_seize;
208 uint8_t mask;
210 if (change && TPM_TIS_IS_VALID_LOCTY(s->s.tis.active_locty)) {
211 is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
212 tis->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
214 if (is_seize) {
215 mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
216 } else {
217 mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
218 TPM_TIS_ACCESS_REQUEST_USE);
220 /* reset flags on the old active locality */
221 tis->loc[s->s.tis.active_locty].access &= mask;
223 if (is_seize) {
224 tis->loc[tis->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
228 tis->active_locty = new_active_locty;
230 DPRINTF("tpm_tis: Active locality is now %d\n", s->s.tis.active_locty);
232 if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
233 /* set flags on the new active locality */
234 tis->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
235 tis->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
236 TPM_TIS_ACCESS_SEIZE);
239 if (change) {
240 tpm_tis_raise_irq(s, tis->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
244 /* abort -- this function switches the locality */
245 static void tpm_tis_abort(TPMState *s, uint8_t locty)
247 TPMTISEmuState *tis = &s->s.tis;
249 tis->loc[locty].r_offset = 0;
250 tis->loc[locty].w_offset = 0;
252 DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis->next_locty);
255 * Need to react differently depending on who's aborting now and
256 * which locality will become active afterwards.
258 if (tis->aborting_locty == tis->next_locty) {
259 tis->loc[tis->aborting_locty].state = TPM_TIS_STATE_READY;
260 tis->loc[tis->aborting_locty].sts = TPM_TIS_STS_COMMAND_READY;
261 tpm_tis_raise_irq(s, tis->aborting_locty, TPM_TIS_INT_COMMAND_READY);
264 /* locality after abort is another one than the current one */
265 tpm_tis_new_active_locality(s, tis->next_locty);
267 tis->next_locty = TPM_TIS_NO_LOCALITY;
268 /* nobody's aborting a command anymore */
269 tis->aborting_locty = TPM_TIS_NO_LOCALITY;
272 /* prepare aborting current command */
273 static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
275 TPMTISEmuState *tis = &s->s.tis;
276 uint8_t busy_locty;
278 tis->aborting_locty = locty;
279 tis->next_locty = newlocty; /* locality after successful abort */
282 * only abort a command using an interrupt if currently executing
283 * a command AND if there's a valid connection to the vTPM.
285 for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
286 if (tis->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
288 * request the backend to cancel. Some backends may not
289 * support it
291 tpm_backend_cancel_cmd(s->be_driver);
292 return;
296 tpm_tis_abort(s, locty);
299 static void tpm_tis_receive_bh(void *opaque)
301 TPMState *s = opaque;
302 TPMTISEmuState *tis = &s->s.tis;
303 uint8_t locty = s->locty_number;
305 tis->loc[locty].sts = TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE;
306 tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
307 tis->loc[locty].r_offset = 0;
308 tis->loc[locty].w_offset = 0;
310 if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) {
311 tpm_tis_abort(s, locty);
314 #ifndef RAISE_STS_IRQ
315 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_DATA_AVAILABLE);
316 #else
317 tpm_tis_raise_irq(s, locty,
318 TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
319 #endif
323 * Callback from the TPM to indicate that the response was received.
325 static void tpm_tis_receive_cb(TPMState *s, uint8_t locty)
327 TPMTISEmuState *tis = &s->s.tis;
329 assert(s->locty_number == locty);
331 qemu_bh_schedule(tis->bh);
335 * Read a byte of response data
337 static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
339 TPMTISEmuState *tis = &s->s.tis;
340 uint32_t ret = TPM_TIS_NO_DATA_BYTE;
341 uint16_t len;
343 if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
344 len = tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
346 ret = tis->loc[locty].r_buffer.buffer[tis->loc[locty].r_offset++];
347 if (tis->loc[locty].r_offset >= len) {
348 /* got last byte */
349 tis->loc[locty].sts = TPM_TIS_STS_VALID;
350 #ifdef RAISE_STS_IRQ
351 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
352 #endif
354 DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x [%d]\n",
355 ret, tis->loc[locty].r_offset-1);
358 return ret;
361 #ifdef DEBUG_TIS
362 static void tpm_tis_dump_state(void *opaque, hwaddr addr)
364 static const unsigned regs[] = {
365 TPM_TIS_REG_ACCESS,
366 TPM_TIS_REG_INT_ENABLE,
367 TPM_TIS_REG_INT_VECTOR,
368 TPM_TIS_REG_INT_STATUS,
369 TPM_TIS_REG_INTF_CAPABILITY,
370 TPM_TIS_REG_STS,
371 TPM_TIS_REG_DID_VID,
372 TPM_TIS_REG_RID,
373 0xfff};
374 int idx;
375 uint8_t locty = tpm_tis_locality_from_addr(addr);
376 hwaddr base = addr & ~0xfff;
377 TPMState *s = opaque;
378 TPMTISEmuState *tis = &s->s.tis;
380 DPRINTF("tpm_tis: active locality : %d\n"
381 "tpm_tis: state of locality %d : %d\n"
382 "tpm_tis: register dump:\n",
383 tis->active_locty,
384 locty, tis->loc[locty].state);
386 for (idx = 0; regs[idx] != 0xfff; idx++) {
387 DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
388 (uint32_t)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
391 DPRINTF("tpm_tis: read offset : %d\n"
392 "tpm_tis: result buffer : ",
393 tis->loc[locty].r_offset);
394 for (idx = 0;
395 idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
396 idx++) {
397 DPRINTF("%c%02x%s",
398 tis->loc[locty].r_offset == idx ? '>' : ' ',
399 tis->loc[locty].r_buffer.buffer[idx],
400 ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
402 DPRINTF("\n"
403 "tpm_tis: write offset : %d\n"
404 "tpm_tis: request buffer: ",
405 tis->loc[locty].w_offset);
406 for (idx = 0;
407 idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
408 idx++) {
409 DPRINTF("%c%02x%s",
410 tis->loc[locty].w_offset == idx ? '>' : ' ',
411 tis->loc[locty].w_buffer.buffer[idx],
412 ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
414 DPRINTF("\n");
416 #endif
419 * Read a register of the TIS interface
420 * See specs pages 33-63 for description of the registers
422 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
423 unsigned size)
425 TPMState *s = opaque;
426 TPMTISEmuState *tis = &s->s.tis;
427 uint16_t offset = addr & 0xffc;
428 uint8_t shift = (addr & 0x3) * 8;
429 uint32_t val = 0xffffffff;
430 uint8_t locty = tpm_tis_locality_from_addr(addr);
431 uint32_t avail;
432 uint8_t v;
434 if (tpm_backend_had_startup_error(s->be_driver)) {
435 return val;
438 switch (offset) {
439 case TPM_TIS_REG_ACCESS:
440 /* never show the SEIZE flag even though we use it internally */
441 val = tis->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
442 /* the pending flag is always calculated */
443 if (tpm_tis_check_request_use_except(s, locty)) {
444 val |= TPM_TIS_ACCESS_PENDING_REQUEST;
446 val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
447 break;
448 case TPM_TIS_REG_INT_ENABLE:
449 val = tis->loc[locty].inte;
450 break;
451 case TPM_TIS_REG_INT_VECTOR:
452 val = tis->irq_num;
453 break;
454 case TPM_TIS_REG_INT_STATUS:
455 val = tis->loc[locty].ints;
456 break;
457 case TPM_TIS_REG_INTF_CAPABILITY:
458 val = TPM_TIS_CAPABILITIES_SUPPORTED;
459 break;
460 case TPM_TIS_REG_STS:
461 if (tis->active_locty == locty) {
462 if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
463 val = TPM_TIS_BURST_COUNT(
464 tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer)
465 - tis->loc[locty].r_offset) | tis->loc[locty].sts;
466 } else {
467 avail = tis->loc[locty].w_buffer.size
468 - tis->loc[locty].w_offset;
470 * byte-sized reads should not return 0x00 for 0x100
471 * available bytes.
473 if (size == 1 && avail > 0xff) {
474 avail = 0xff;
476 val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts;
479 break;
480 case TPM_TIS_REG_DATA_FIFO:
481 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
482 if (tis->active_locty == locty) {
483 if (size > 4 - (addr & 0x3)) {
484 /* prevent access beyond FIFO */
485 size = 4 - (addr & 0x3);
487 val = 0;
488 shift = 0;
489 while (size > 0) {
490 switch (tis->loc[locty].state) {
491 case TPM_TIS_STATE_COMPLETION:
492 v = tpm_tis_data_read(s, locty);
493 break;
494 default:
495 v = TPM_TIS_NO_DATA_BYTE;
496 break;
498 val |= (v << shift);
499 shift += 8;
500 size--;
502 shift = 0; /* no more adjustments */
504 break;
505 case TPM_TIS_REG_DID_VID:
506 val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
507 break;
508 case TPM_TIS_REG_RID:
509 val = TPM_TIS_TPM_RID;
510 break;
511 #ifdef DEBUG_TIS
512 case TPM_TIS_REG_DEBUG:
513 tpm_tis_dump_state(opaque, addr);
514 break;
515 #endif
518 if (shift) {
519 val >>= shift;
522 DPRINTF("tpm_tis: read.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
524 return val;
528 * Write a value to a register of the TIS interface
529 * See specs pages 33-63 for description of the registers
531 static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
532 uint64_t val, unsigned size,
533 bool hw_access)
535 TPMState *s = opaque;
536 TPMTISEmuState *tis = &s->s.tis;
537 uint16_t off = addr & 0xffc;
538 uint8_t shift = (addr & 0x3) * 8;
539 uint8_t locty = tpm_tis_locality_from_addr(addr);
540 uint8_t active_locty, l;
541 int c, set_new_locty = 1;
542 uint16_t len;
543 uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);
545 DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (uint32_t)val);
547 if (locty == 4 && !hw_access) {
548 DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
549 return;
552 if (tpm_backend_had_startup_error(s->be_driver)) {
553 return;
556 val &= mask;
558 if (shift) {
559 val <<= shift;
560 mask <<= shift;
563 mask ^= 0xffffffff;
565 switch (off) {
566 case TPM_TIS_REG_ACCESS:
568 if ((val & TPM_TIS_ACCESS_SEIZE)) {
569 val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
570 TPM_TIS_ACCESS_ACTIVE_LOCALITY);
573 active_locty = tis->active_locty;
575 if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
576 /* give up locality if currently owned */
577 if (tis->active_locty == locty) {
578 DPRINTF("tpm_tis: Releasing locality %d\n", locty);
580 uint8_t newlocty = TPM_TIS_NO_LOCALITY;
581 /* anybody wants the locality ? */
582 for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
583 if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
584 DPRINTF("tpm_tis: Locality %d requests use.\n", c);
585 newlocty = c;
586 break;
589 DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
590 "Next active locality: %d\n",
591 newlocty);
593 if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
594 set_new_locty = 0;
595 tpm_tis_prep_abort(s, locty, newlocty);
596 } else {
597 active_locty = TPM_TIS_NO_LOCALITY;
599 } else {
600 /* not currently the owner; clear a pending request */
601 tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
605 if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
606 tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
609 if ((val & TPM_TIS_ACCESS_SEIZE)) {
611 * allow seize if a locality is active and the requesting
612 * locality is higher than the one that's active
613 * OR
614 * allow seize for requesting locality if no locality is
615 * active
617 while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&
618 locty > tis->active_locty) ||
619 !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
620 bool higher_seize = FALSE;
622 /* already a pending SEIZE ? */
623 if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
624 break;
627 /* check for ongoing seize by a higher locality */
628 for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
629 if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
630 higher_seize = TRUE;
631 break;
635 if (higher_seize) {
636 break;
639 /* cancel any seize by a lower locality */
640 for (l = 0; l < locty - 1; l++) {
641 tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
644 tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
645 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
646 "Locality %d seized from locality %d\n",
647 locty, tis->active_locty);
648 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");
649 set_new_locty = 0;
650 tpm_tis_prep_abort(s, tis->active_locty, locty);
651 break;
655 if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
656 if (tis->active_locty != locty) {
657 if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
658 tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
659 } else {
660 /* no locality active -> make this one active now */
661 active_locty = locty;
666 if (set_new_locty) {
667 tpm_tis_new_active_locality(s, active_locty);
670 break;
671 case TPM_TIS_REG_INT_ENABLE:
672 if (tis->active_locty != locty) {
673 break;
676 tis->loc[locty].inte &= mask;
677 tis->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED |
678 TPM_TIS_INT_POLARITY_MASK |
679 TPM_TIS_INTERRUPTS_SUPPORTED));
680 break;
681 case TPM_TIS_REG_INT_VECTOR:
682 /* hard wired -- ignore */
683 break;
684 case TPM_TIS_REG_INT_STATUS:
685 if (tis->active_locty != locty) {
686 break;
689 /* clearing of interrupt flags */
690 if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
691 (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
692 tis->loc[locty].ints &= ~val;
693 if (tis->loc[locty].ints == 0) {
694 qemu_irq_lower(tis->irq);
695 DPRINTF("tpm_tis: Lowering IRQ\n");
698 tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
699 break;
700 case TPM_TIS_REG_STS:
701 if (tis->active_locty != locty) {
702 break;
705 val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
706 TPM_TIS_STS_RESPONSE_RETRY);
708 if (val == TPM_TIS_STS_COMMAND_READY) {
709 switch (tis->loc[locty].state) {
711 case TPM_TIS_STATE_READY:
712 tis->loc[locty].w_offset = 0;
713 tis->loc[locty].r_offset = 0;
714 break;
716 case TPM_TIS_STATE_IDLE:
717 tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;
718 tis->loc[locty].state = TPM_TIS_STATE_READY;
719 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
720 break;
722 case TPM_TIS_STATE_EXECUTION:
723 case TPM_TIS_STATE_RECEPTION:
724 /* abort currently running command */
725 DPRINTF("tpm_tis: %s: Initiating abort.\n",
726 __func__);
727 tpm_tis_prep_abort(s, locty, locty);
728 break;
730 case TPM_TIS_STATE_COMPLETION:
731 tis->loc[locty].w_offset = 0;
732 tis->loc[locty].r_offset = 0;
733 /* shortcut to ready state with C/R set */
734 tis->loc[locty].state = TPM_TIS_STATE_READY;
735 if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
736 tis->loc[locty].sts = TPM_TIS_STS_COMMAND_READY;
737 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
739 tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
740 break;
743 } else if (val == TPM_TIS_STS_TPM_GO) {
744 switch (tis->loc[locty].state) {
745 case TPM_TIS_STATE_RECEPTION:
746 if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
747 tpm_tis_tpm_send(s, locty);
749 break;
750 default:
751 /* ignore */
752 break;
754 } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
755 switch (tis->loc[locty].state) {
756 case TPM_TIS_STATE_COMPLETION:
757 tis->loc[locty].r_offset = 0;
758 tis->loc[locty].sts = TPM_TIS_STS_VALID |
759 TPM_TIS_STS_DATA_AVAILABLE;
760 break;
761 default:
762 /* ignore */
763 break;
766 break;
767 case TPM_TIS_REG_DATA_FIFO:
768 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
769 /* data fifo */
770 if (tis->active_locty != locty) {
771 break;
774 if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||
775 tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
776 tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
777 /* drop the byte */
778 } else {
779 DPRINTF("tpm_tis: Data to send to TPM: %08x (size=%d)\n",
780 val, size);
781 if (tis->loc[locty].state == TPM_TIS_STATE_READY) {
782 tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;
783 tis->loc[locty].sts = TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID;
786 val >>= shift;
787 if (size > 4 - (addr & 0x3)) {
788 /* prevent access beyond FIFO */
789 size = 4 - (addr & 0x3);
792 while ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {
793 if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {
794 tis->loc[locty].w_buffer.
795 buffer[tis->loc[locty].w_offset++] = (uint8_t)val;
796 val >>= 8;
797 size--;
798 } else {
799 tis->loc[locty].sts = TPM_TIS_STS_VALID;
803 /* check for complete packet */
804 if (tis->loc[locty].w_offset > 5 &&
805 (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
806 /* we have a packet length - see if we have all of it */
807 #ifdef RAISE_STS_IRQ
808 bool needIrq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);
809 #endif
810 len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
811 if (len > tis->loc[locty].w_offset) {
812 tis->loc[locty].sts = TPM_TIS_STS_EXPECT |
813 TPM_TIS_STS_VALID;
814 } else {
815 /* packet complete */
816 tis->loc[locty].sts = TPM_TIS_STS_VALID;
818 #ifdef RAISE_STS_IRQ
819 if (needIrq) {
820 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
822 #endif
825 break;
829 static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
830 uint64_t val, unsigned size)
832 return tpm_tis_mmio_write_intern(opaque, addr, val, size, false);
835 static const MemoryRegionOps tpm_tis_memory_ops = {
836 .read = tpm_tis_mmio_read,
837 .write = tpm_tis_mmio_write,
838 .endianness = DEVICE_LITTLE_ENDIAN,
839 .valid = {
840 .min_access_size = 1,
841 .max_access_size = 4,
845 static int tpm_tis_do_startup_tpm(TPMState *s)
847 return tpm_backend_startup_tpm(s->be_driver);
851 * This function is called when the machine starts, resets or due to
852 * S3 resume.
854 static void tpm_tis_reset(DeviceState *dev)
856 TPMState *s = TPM(dev);
857 TPMTISEmuState *tis = &s->s.tis;
858 int c;
860 tpm_backend_reset(s->be_driver);
862 tis->active_locty = TPM_TIS_NO_LOCALITY;
863 tis->next_locty = TPM_TIS_NO_LOCALITY;
864 tis->aborting_locty = TPM_TIS_NO_LOCALITY;
866 for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
867 tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
868 tis->loc[c].sts = 0;
869 tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
870 tis->loc[c].ints = 0;
871 tis->loc[c].state = TPM_TIS_STATE_IDLE;
873 tis->loc[c].w_offset = 0;
874 tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer);
875 tis->loc[c].r_offset = 0;
876 tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer);
879 tpm_tis_do_startup_tpm(s);
882 static const VMStateDescription vmstate_tpm_tis = {
883 .name = "tpm",
884 .unmigratable = 1,
887 static Property tpm_tis_properties[] = {
888 DEFINE_PROP_UINT32("irq", TPMState,
889 s.tis.irq_num, TPM_TIS_IRQ),
890 DEFINE_PROP_STRING("tpmdev", TPMState, backend),
891 DEFINE_PROP_END_OF_LIST(),
894 static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
896 TPMState *s = TPM(dev);
897 TPMTISEmuState *tis = &s->s.tis;
899 s->be_driver = qemu_find_tpm(s->backend);
900 if (!s->be_driver) {
901 error_setg(errp, "tpm_tis: backend driver with id %s could not be "
902 "found", s->backend);
903 return;
906 s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
908 if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
909 error_setg(errp, "tpm_tis: backend driver with id %s could not be "
910 "initialized", s->backend);
911 return;
914 if (tis->irq_num > 15) {
915 error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
916 "of 0 to 15.\n", tis->irq_num);
917 return;
920 tis->bh = qemu_bh_new(tpm_tis_receive_bh, s);
922 isa_init_irq(&s->busdev, &tis->irq, tis->irq_num);
925 static void tpm_tis_initfn(Object *obj)
927 ISADevice *dev = ISA_DEVICE(obj);
928 TPMState *s = TPM(obj);
930 memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
931 s, "tpm-tis-mmio",
932 TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
933 memory_region_add_subregion(isa_address_space(dev), TPM_TIS_ADDR_BASE,
934 &s->mmio);
937 static void tpm_tis_class_init(ObjectClass *klass, void *data)
939 DeviceClass *dc = DEVICE_CLASS(klass);
941 dc->realize = tpm_tis_realizefn;
942 dc->props = tpm_tis_properties;
943 dc->reset = tpm_tis_reset;
944 dc->vmsd = &vmstate_tpm_tis;
947 static const TypeInfo tpm_tis_info = {
948 .name = TYPE_TPM_TIS,
949 .parent = TYPE_ISA_DEVICE,
950 .instance_size = sizeof(TPMState),
951 .instance_init = tpm_tis_initfn,
952 .class_init = tpm_tis_class_init,
955 static void tpm_tis_register(void)
957 type_register_static(&tpm_tis_info);
958 tpm_register_model(TPM_MODEL_TPM_TIS);
961 type_init(tpm_tis_register)