nbd-server: do not check request length except for reads and writes
[qemu/ar7.git] / hw / tpm / tpm_tis.c
blob95fc66e8fcaf44098f3c46abf4dfaf7110345bf4
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.3, 21 March 2013
18 * In the developers menu choose the PC Client section then find the TIS
19 * specification.
21 * TPM TIS for TPM 2 implementation following TCG PC Client Platform
22 * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
25 #include "sysemu/tpm_backend.h"
26 #include "tpm_int.h"
27 #include "sysemu/block-backend.h"
28 #include "exec/address-spaces.h"
29 #include "hw/hw.h"
30 #include "hw/i386/pc.h"
31 #include "hw/pci/pci_ids.h"
32 #include "tpm_tis.h"
33 #include "qemu-common.h"
34 #include "qemu/main-loop.h"
35 #include "sysemu/tpm_backend.h"
37 #define DEBUG_TIS 0
39 #define DPRINTF(fmt, ...) do { \
40 if (DEBUG_TIS) { \
41 printf(fmt, ## __VA_ARGS__); \
42 } \
43 } while (0);
45 /* whether the STS interrupt is supported */
46 #define RAISE_STS_IRQ
48 /* tis registers */
49 #define TPM_TIS_REG_ACCESS 0x00
50 #define TPM_TIS_REG_INT_ENABLE 0x08
51 #define TPM_TIS_REG_INT_VECTOR 0x0c
52 #define TPM_TIS_REG_INT_STATUS 0x10
53 #define TPM_TIS_REG_INTF_CAPABILITY 0x14
54 #define TPM_TIS_REG_STS 0x18
55 #define TPM_TIS_REG_DATA_FIFO 0x24
56 #define TPM_TIS_REG_INTERFACE_ID 0x30
57 #define TPM_TIS_REG_DATA_XFIFO 0x80
58 #define TPM_TIS_REG_DATA_XFIFO_END 0xbc
59 #define TPM_TIS_REG_DID_VID 0xf00
60 #define TPM_TIS_REG_RID 0xf04
62 /* vendor-specific registers */
63 #define TPM_TIS_REG_DEBUG 0xf90
65 #define TPM_TIS_STS_TPM_FAMILY_MASK (0x3 << 26)/* TPM 2.0 */
66 #define TPM_TIS_STS_TPM_FAMILY1_2 (0 << 26) /* TPM 2.0 */
67 #define TPM_TIS_STS_TPM_FAMILY2_0 (1 << 26) /* TPM 2.0 */
68 #define TPM_TIS_STS_RESET_ESTABLISHMENT_BIT (1 << 25) /* TPM 2.0 */
69 #define TPM_TIS_STS_COMMAND_CANCEL (1 << 24) /* TPM 2.0 */
71 #define TPM_TIS_STS_VALID (1 << 7)
72 #define TPM_TIS_STS_COMMAND_READY (1 << 6)
73 #define TPM_TIS_STS_TPM_GO (1 << 5)
74 #define TPM_TIS_STS_DATA_AVAILABLE (1 << 4)
75 #define TPM_TIS_STS_EXPECT (1 << 3)
76 #define TPM_TIS_STS_SELFTEST_DONE (1 << 2)
77 #define TPM_TIS_STS_RESPONSE_RETRY (1 << 1)
79 #define TPM_TIS_BURST_COUNT_SHIFT 8
80 #define TPM_TIS_BURST_COUNT(X) \
81 ((X) << TPM_TIS_BURST_COUNT_SHIFT)
83 #define TPM_TIS_ACCESS_TPM_REG_VALID_STS (1 << 7)
84 #define TPM_TIS_ACCESS_ACTIVE_LOCALITY (1 << 5)
85 #define TPM_TIS_ACCESS_BEEN_SEIZED (1 << 4)
86 #define TPM_TIS_ACCESS_SEIZE (1 << 3)
87 #define TPM_TIS_ACCESS_PENDING_REQUEST (1 << 2)
88 #define TPM_TIS_ACCESS_REQUEST_USE (1 << 1)
89 #define TPM_TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0)
91 #define TPM_TIS_INT_ENABLED (1 << 31)
92 #define TPM_TIS_INT_DATA_AVAILABLE (1 << 0)
93 #define TPM_TIS_INT_STS_VALID (1 << 1)
94 #define TPM_TIS_INT_LOCALITY_CHANGED (1 << 2)
95 #define TPM_TIS_INT_COMMAND_READY (1 << 7)
97 #define TPM_TIS_INT_POLARITY_MASK (3 << 3)
98 #define TPM_TIS_INT_POLARITY_LOW_LEVEL (1 << 3)
100 #ifndef RAISE_STS_IRQ
102 #define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
103 TPM_TIS_INT_DATA_AVAILABLE | \
104 TPM_TIS_INT_COMMAND_READY)
106 #else
108 #define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
109 TPM_TIS_INT_DATA_AVAILABLE | \
110 TPM_TIS_INT_STS_VALID | \
111 TPM_TIS_INT_COMMAND_READY)
113 #endif
115 #define TPM_TIS_CAP_INTERFACE_VERSION1_3 (2 << 28)
116 #define TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 (3 << 28)
117 #define TPM_TIS_CAP_DATA_TRANSFER_64B (3 << 9)
118 #define TPM_TIS_CAP_DATA_TRANSFER_LEGACY (0 << 9)
119 #define TPM_TIS_CAP_BURST_COUNT_DYNAMIC (0 << 8)
120 #define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */
121 #define TPM_TIS_CAPABILITIES_SUPPORTED1_3 \
122 (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
123 TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
124 TPM_TIS_CAP_DATA_TRANSFER_64B | \
125 TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
126 TPM_TIS_INTERRUPTS_SUPPORTED)
128 #define TPM_TIS_CAPABILITIES_SUPPORTED2_0 \
129 (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
130 TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
131 TPM_TIS_CAP_DATA_TRANSFER_64B | \
132 TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 | \
133 TPM_TIS_INTERRUPTS_SUPPORTED)
135 #define TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 (0xf) /* TPM 2.0 */
136 #define TPM_TIS_IFACE_ID_INTERFACE_FIFO (0x0) /* TPM 2.0 */
137 #define TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO (0 << 4) /* TPM 2.0 */
138 #define TPM_TIS_IFACE_ID_CAP_5_LOCALITIES (1 << 8) /* TPM 2.0 */
139 #define TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED (1 << 13) /* TPM 2.0 */
140 #define TPM_TIS_IFACE_ID_INT_SEL_LOCK (1 << 19) /* TPM 2.0 */
142 #define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3 \
143 (TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 | \
144 (~0u << 4)/* all of it is don't care */)
146 /* if backend was a TPM 2.0: */
147 #define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0 \
148 (TPM_TIS_IFACE_ID_INTERFACE_FIFO | \
149 TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO | \
150 TPM_TIS_IFACE_ID_CAP_5_LOCALITIES | \
151 TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED)
153 #define TPM_TIS_TPM_DID 0x0001
154 #define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM
155 #define TPM_TIS_TPM_RID 0x0001
157 #define TPM_TIS_NO_DATA_BYTE 0xff
159 /* local prototypes */
161 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
162 unsigned size);
164 /* utility functions */
166 static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
168 return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
171 static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
173 return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
176 static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
178 #ifdef DEBUG_TIS
179 uint32_t len, i;
181 len = tpm_tis_get_size_from_buffer(sb);
182 DPRINTF("tpm_tis: %s length = %d\n", string, len);
183 for (i = 0; i < len; i++) {
184 if (i && !(i % 16)) {
185 DPRINTF("\n");
187 DPRINTF("%.2X ", sb->buffer[i]);
189 DPRINTF("\n");
190 #endif
194 * Set the given flags in the STS register by clearing the register but
195 * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting
196 * the new flags.
198 * The SELFTEST_DONE flag is acquired from the backend that determines it by
199 * peeking into TPM commands.
201 * A VM suspend/resume will preserve the flag by storing it into the VM
202 * device state, but the backend will not remember it when QEMU is started
203 * again. Therefore, we cache the flag here. Once set, it will not be unset
204 * except by a reset.
206 static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
208 l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK;
209 l->sts |= flags;
213 * Send a request to the TPM.
215 static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
217 TPMTISEmuState *tis = &s->s.tis;
219 tpm_tis_show_buffer(&tis->loc[locty].w_buffer, "tpm_tis: To TPM");
221 s->locty_number = locty;
222 s->locty_data = &tis->loc[locty];
225 * w_offset serves as length indicator for length of data;
226 * it's reset when the response comes back
228 tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
230 tpm_backend_deliver_request(s->be_driver);
233 /* raise an interrupt if allowed */
234 static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
236 TPMTISEmuState *tis = &s->s.tis;
238 if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
239 return;
242 if ((tis->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
243 (tis->loc[locty].inte & irqmask)) {
244 DPRINTF("tpm_tis: Raising IRQ for flag %08x\n", irqmask);
245 qemu_irq_raise(s->s.tis.irq);
246 tis->loc[locty].ints |= irqmask;
250 static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
252 uint8_t l;
254 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
255 if (l == locty) {
256 continue;
258 if ((s->s.tis.loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
259 return 1;
263 return 0;
266 static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
268 TPMTISEmuState *tis = &s->s.tis;
269 bool change = (s->s.tis.active_locty != new_active_locty);
270 bool is_seize;
271 uint8_t mask;
273 if (change && TPM_TIS_IS_VALID_LOCTY(s->s.tis.active_locty)) {
274 is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
275 tis->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
277 if (is_seize) {
278 mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
279 } else {
280 mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
281 TPM_TIS_ACCESS_REQUEST_USE);
283 /* reset flags on the old active locality */
284 tis->loc[s->s.tis.active_locty].access &= mask;
286 if (is_seize) {
287 tis->loc[tis->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
291 tis->active_locty = new_active_locty;
293 DPRINTF("tpm_tis: Active locality is now %d\n", s->s.tis.active_locty);
295 if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
296 /* set flags on the new active locality */
297 tis->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
298 tis->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
299 TPM_TIS_ACCESS_SEIZE);
302 if (change) {
303 tpm_tis_raise_irq(s, tis->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
307 /* abort -- this function switches the locality */
308 static void tpm_tis_abort(TPMState *s, uint8_t locty)
310 TPMTISEmuState *tis = &s->s.tis;
312 tis->loc[locty].r_offset = 0;
313 tis->loc[locty].w_offset = 0;
315 DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis->next_locty);
318 * Need to react differently depending on who's aborting now and
319 * which locality will become active afterwards.
321 if (tis->aborting_locty == tis->next_locty) {
322 tis->loc[tis->aborting_locty].state = TPM_TIS_STATE_READY;
323 tpm_tis_sts_set(&tis->loc[tis->aborting_locty],
324 TPM_TIS_STS_COMMAND_READY);
325 tpm_tis_raise_irq(s, tis->aborting_locty, TPM_TIS_INT_COMMAND_READY);
328 /* locality after abort is another one than the current one */
329 tpm_tis_new_active_locality(s, tis->next_locty);
331 tis->next_locty = TPM_TIS_NO_LOCALITY;
332 /* nobody's aborting a command anymore */
333 tis->aborting_locty = TPM_TIS_NO_LOCALITY;
336 /* prepare aborting current command */
337 static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
339 TPMTISEmuState *tis = &s->s.tis;
340 uint8_t busy_locty;
342 tis->aborting_locty = locty;
343 tis->next_locty = newlocty; /* locality after successful abort */
346 * only abort a command using an interrupt if currently executing
347 * a command AND if there's a valid connection to the vTPM.
349 for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
350 if (tis->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
352 * request the backend to cancel. Some backends may not
353 * support it
355 tpm_backend_cancel_cmd(s->be_driver);
356 return;
360 tpm_tis_abort(s, locty);
363 static void tpm_tis_receive_bh(void *opaque)
365 TPMState *s = opaque;
366 TPMTISEmuState *tis = &s->s.tis;
367 uint8_t locty = s->locty_number;
369 tpm_tis_sts_set(&tis->loc[locty],
370 TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
371 tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
372 tis->loc[locty].r_offset = 0;
373 tis->loc[locty].w_offset = 0;
375 if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) {
376 tpm_tis_abort(s, locty);
379 #ifndef RAISE_STS_IRQ
380 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_DATA_AVAILABLE);
381 #else
382 tpm_tis_raise_irq(s, locty,
383 TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
384 #endif
388 * Callback from the TPM to indicate that the response was received.
390 static void tpm_tis_receive_cb(TPMState *s, uint8_t locty,
391 bool is_selftest_done)
393 TPMTISEmuState *tis = &s->s.tis;
394 uint8_t l;
396 assert(s->locty_number == locty);
398 if (is_selftest_done) {
399 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
400 tis->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE;
404 qemu_bh_schedule(tis->bh);
408 * Read a byte of response data
410 static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
412 TPMTISEmuState *tis = &s->s.tis;
413 uint32_t ret = TPM_TIS_NO_DATA_BYTE;
414 uint16_t len;
416 if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
417 len = tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
419 ret = tis->loc[locty].r_buffer.buffer[tis->loc[locty].r_offset++];
420 if (tis->loc[locty].r_offset >= len) {
421 /* got last byte */
422 tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_VALID);
423 #ifdef RAISE_STS_IRQ
424 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
425 #endif
427 DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x [%d]\n",
428 ret, tis->loc[locty].r_offset-1);
431 return ret;
434 #ifdef DEBUG_TIS
435 static void tpm_tis_dump_state(void *opaque, hwaddr addr)
437 static const unsigned regs[] = {
438 TPM_TIS_REG_ACCESS,
439 TPM_TIS_REG_INT_ENABLE,
440 TPM_TIS_REG_INT_VECTOR,
441 TPM_TIS_REG_INT_STATUS,
442 TPM_TIS_REG_INTF_CAPABILITY,
443 TPM_TIS_REG_STS,
444 TPM_TIS_REG_DID_VID,
445 TPM_TIS_REG_RID,
446 0xfff};
447 int idx;
448 uint8_t locty = tpm_tis_locality_from_addr(addr);
449 hwaddr base = addr & ~0xfff;
450 TPMState *s = opaque;
451 TPMTISEmuState *tis = &s->s.tis;
453 DPRINTF("tpm_tis: active locality : %d\n"
454 "tpm_tis: state of locality %d : %d\n"
455 "tpm_tis: register dump:\n",
456 tis->active_locty,
457 locty, tis->loc[locty].state);
459 for (idx = 0; regs[idx] != 0xfff; idx++) {
460 DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
461 (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
464 DPRINTF("tpm_tis: read offset : %d\n"
465 "tpm_tis: result buffer : ",
466 tis->loc[locty].r_offset);
467 for (idx = 0;
468 idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
469 idx++) {
470 DPRINTF("%c%02x%s",
471 tis->loc[locty].r_offset == idx ? '>' : ' ',
472 tis->loc[locty].r_buffer.buffer[idx],
473 ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
475 DPRINTF("\n"
476 "tpm_tis: write offset : %d\n"
477 "tpm_tis: request buffer: ",
478 tis->loc[locty].w_offset);
479 for (idx = 0;
480 idx < tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
481 idx++) {
482 DPRINTF("%c%02x%s",
483 tis->loc[locty].w_offset == idx ? '>' : ' ',
484 tis->loc[locty].w_buffer.buffer[idx],
485 ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : "");
487 DPRINTF("\n");
489 #endif
492 * Read a register of the TIS interface
493 * See specs pages 33-63 for description of the registers
495 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
496 unsigned size)
498 TPMState *s = opaque;
499 TPMTISEmuState *tis = &s->s.tis;
500 uint16_t offset = addr & 0xffc;
501 uint8_t shift = (addr & 0x3) * 8;
502 uint32_t val = 0xffffffff;
503 uint8_t locty = tpm_tis_locality_from_addr(addr);
504 uint32_t avail;
505 uint8_t v;
507 if (tpm_backend_had_startup_error(s->be_driver)) {
508 return val;
511 switch (offset) {
512 case TPM_TIS_REG_ACCESS:
513 /* never show the SEIZE flag even though we use it internally */
514 val = tis->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE;
515 /* the pending flag is always calculated */
516 if (tpm_tis_check_request_use_except(s, locty)) {
517 val |= TPM_TIS_ACCESS_PENDING_REQUEST;
519 val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
520 break;
521 case TPM_TIS_REG_INT_ENABLE:
522 val = tis->loc[locty].inte;
523 break;
524 case TPM_TIS_REG_INT_VECTOR:
525 val = tis->irq_num;
526 break;
527 case TPM_TIS_REG_INT_STATUS:
528 val = tis->loc[locty].ints;
529 break;
530 case TPM_TIS_REG_INTF_CAPABILITY:
531 switch (s->be_tpm_version) {
532 case TPM_VERSION_UNSPEC:
533 val = 0;
534 break;
535 case TPM_VERSION_1_2:
536 val = TPM_TIS_CAPABILITIES_SUPPORTED1_3;
537 break;
538 case TPM_VERSION_2_0:
539 val = TPM_TIS_CAPABILITIES_SUPPORTED2_0;
540 break;
542 break;
543 case TPM_TIS_REG_STS:
544 if (tis->active_locty == locty) {
545 if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
546 val = TPM_TIS_BURST_COUNT(
547 tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer)
548 - tis->loc[locty].r_offset) | tis->loc[locty].sts;
549 } else {
550 avail = tis->loc[locty].w_buffer.size
551 - tis->loc[locty].w_offset;
553 * byte-sized reads should not return 0x00 for 0x100
554 * available bytes.
556 if (size == 1 && avail > 0xff) {
557 avail = 0xff;
559 val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts;
562 break;
563 case TPM_TIS_REG_DATA_FIFO:
564 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
565 if (tis->active_locty == locty) {
566 if (size > 4 - (addr & 0x3)) {
567 /* prevent access beyond FIFO */
568 size = 4 - (addr & 0x3);
570 val = 0;
571 shift = 0;
572 while (size > 0) {
573 switch (tis->loc[locty].state) {
574 case TPM_TIS_STATE_COMPLETION:
575 v = tpm_tis_data_read(s, locty);
576 break;
577 default:
578 v = TPM_TIS_NO_DATA_BYTE;
579 break;
581 val |= (v << shift);
582 shift += 8;
583 size--;
585 shift = 0; /* no more adjustments */
587 break;
588 case TPM_TIS_REG_INTERFACE_ID:
589 val = tis->loc[locty].iface_id;
590 break;
591 case TPM_TIS_REG_DID_VID:
592 val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
593 break;
594 case TPM_TIS_REG_RID:
595 val = TPM_TIS_TPM_RID;
596 break;
597 #ifdef DEBUG_TIS
598 case TPM_TIS_REG_DEBUG:
599 tpm_tis_dump_state(opaque, addr);
600 break;
601 #endif
604 if (shift) {
605 val >>= shift;
608 DPRINTF("tpm_tis: read.%u(%08x) = %08x\n", size, (int)addr, (int)val);
610 return val;
614 * Write a value to a register of the TIS interface
615 * See specs pages 33-63 for description of the registers
617 static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
618 uint64_t val, unsigned size,
619 bool hw_access)
621 TPMState *s = opaque;
622 TPMTISEmuState *tis = &s->s.tis;
623 uint16_t off = addr & 0xffc;
624 uint8_t shift = (addr & 0x3) * 8;
625 uint8_t locty = tpm_tis_locality_from_addr(addr);
626 uint8_t active_locty, l;
627 int c, set_new_locty = 1;
628 uint16_t len;
629 uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);
631 DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (int)val);
633 if (locty == 4 && !hw_access) {
634 DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
635 return;
638 if (tpm_backend_had_startup_error(s->be_driver)) {
639 return;
642 val &= mask;
644 if (shift) {
645 val <<= shift;
646 mask <<= shift;
649 mask ^= 0xffffffff;
651 switch (off) {
652 case TPM_TIS_REG_ACCESS:
654 if ((val & TPM_TIS_ACCESS_SEIZE)) {
655 val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
656 TPM_TIS_ACCESS_ACTIVE_LOCALITY);
659 active_locty = tis->active_locty;
661 if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) {
662 /* give up locality if currently owned */
663 if (tis->active_locty == locty) {
664 DPRINTF("tpm_tis: Releasing locality %d\n", locty);
666 uint8_t newlocty = TPM_TIS_NO_LOCALITY;
667 /* anybody wants the locality ? */
668 for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) {
669 if ((tis->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) {
670 DPRINTF("tpm_tis: Locality %d requests use.\n", c);
671 newlocty = c;
672 break;
675 DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
676 "Next active locality: %d\n",
677 newlocty);
679 if (TPM_TIS_IS_VALID_LOCTY(newlocty)) {
680 set_new_locty = 0;
681 tpm_tis_prep_abort(s, locty, newlocty);
682 } else {
683 active_locty = TPM_TIS_NO_LOCALITY;
685 } else {
686 /* not currently the owner; clear a pending request */
687 tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
691 if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
692 tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
695 if ((val & TPM_TIS_ACCESS_SEIZE)) {
697 * allow seize if a locality is active and the requesting
698 * locality is higher than the one that's active
699 * OR
700 * allow seize for requesting locality if no locality is
701 * active
703 while ((TPM_TIS_IS_VALID_LOCTY(tis->active_locty) &&
704 locty > tis->active_locty) ||
705 !TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
706 bool higher_seize = FALSE;
708 /* already a pending SEIZE ? */
709 if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
710 break;
713 /* check for ongoing seize by a higher locality */
714 for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) {
715 if ((tis->loc[l].access & TPM_TIS_ACCESS_SEIZE)) {
716 higher_seize = TRUE;
717 break;
721 if (higher_seize) {
722 break;
725 /* cancel any seize by a lower locality */
726 for (l = 0; l < locty - 1; l++) {
727 tis->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE;
730 tis->loc[locty].access |= TPM_TIS_ACCESS_SEIZE;
731 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
732 "Locality %d seized from locality %d\n",
733 locty, tis->active_locty);
734 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");
735 set_new_locty = 0;
736 tpm_tis_prep_abort(s, tis->active_locty, locty);
737 break;
741 if ((val & TPM_TIS_ACCESS_REQUEST_USE)) {
742 if (tis->active_locty != locty) {
743 if (TPM_TIS_IS_VALID_LOCTY(tis->active_locty)) {
744 tis->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE;
745 } else {
746 /* no locality active -> make this one active now */
747 active_locty = locty;
752 if (set_new_locty) {
753 tpm_tis_new_active_locality(s, active_locty);
756 break;
757 case TPM_TIS_REG_INT_ENABLE:
758 if (tis->active_locty != locty) {
759 break;
762 tis->loc[locty].inte &= mask;
763 tis->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED |
764 TPM_TIS_INT_POLARITY_MASK |
765 TPM_TIS_INTERRUPTS_SUPPORTED));
766 break;
767 case TPM_TIS_REG_INT_VECTOR:
768 /* hard wired -- ignore */
769 break;
770 case TPM_TIS_REG_INT_STATUS:
771 if (tis->active_locty != locty) {
772 break;
775 /* clearing of interrupt flags */
776 if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) &&
777 (tis->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) {
778 tis->loc[locty].ints &= ~val;
779 if (tis->loc[locty].ints == 0) {
780 qemu_irq_lower(tis->irq);
781 DPRINTF("tpm_tis: Lowering IRQ\n");
784 tis->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED);
785 break;
786 case TPM_TIS_REG_STS:
787 if (tis->active_locty != locty) {
788 break;
791 if (s->be_tpm_version == TPM_VERSION_2_0) {
792 /* some flags that are only supported for TPM 2 */
793 if (val & TPM_TIS_STS_COMMAND_CANCEL) {
794 if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
796 * request the backend to cancel. Some backends may not
797 * support it
799 tpm_backend_cancel_cmd(s->be_driver);
803 if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) {
804 if (locty == 3 || locty == 4) {
805 tpm_backend_reset_tpm_established_flag(s->be_driver, locty);
810 val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
811 TPM_TIS_STS_RESPONSE_RETRY);
813 if (val == TPM_TIS_STS_COMMAND_READY) {
814 switch (tis->loc[locty].state) {
816 case TPM_TIS_STATE_READY:
817 tis->loc[locty].w_offset = 0;
818 tis->loc[locty].r_offset = 0;
819 break;
821 case TPM_TIS_STATE_IDLE:
822 tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_COMMAND_READY);
823 tis->loc[locty].state = TPM_TIS_STATE_READY;
824 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
825 break;
827 case TPM_TIS_STATE_EXECUTION:
828 case TPM_TIS_STATE_RECEPTION:
829 /* abort currently running command */
830 DPRINTF("tpm_tis: %s: Initiating abort.\n",
831 __func__);
832 tpm_tis_prep_abort(s, locty, locty);
833 break;
835 case TPM_TIS_STATE_COMPLETION:
836 tis->loc[locty].w_offset = 0;
837 tis->loc[locty].r_offset = 0;
838 /* shortcut to ready state with C/R set */
839 tis->loc[locty].state = TPM_TIS_STATE_READY;
840 if (!(tis->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) {
841 tpm_tis_sts_set(&tis->loc[locty],
842 TPM_TIS_STS_COMMAND_READY);
843 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
845 tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
846 break;
849 } else if (val == TPM_TIS_STS_TPM_GO) {
850 switch (tis->loc[locty].state) {
851 case TPM_TIS_STATE_RECEPTION:
852 if ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) {
853 tpm_tis_tpm_send(s, locty);
855 break;
856 default:
857 /* ignore */
858 break;
860 } else if (val == TPM_TIS_STS_RESPONSE_RETRY) {
861 switch (tis->loc[locty].state) {
862 case TPM_TIS_STATE_COMPLETION:
863 tis->loc[locty].r_offset = 0;
864 tpm_tis_sts_set(&tis->loc[locty],
865 TPM_TIS_STS_VALID|
866 TPM_TIS_STS_DATA_AVAILABLE);
867 break;
868 default:
869 /* ignore */
870 break;
873 break;
874 case TPM_TIS_REG_DATA_FIFO:
875 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
876 /* data fifo */
877 if (tis->active_locty != locty) {
878 break;
881 if (tis->loc[locty].state == TPM_TIS_STATE_IDLE ||
882 tis->loc[locty].state == TPM_TIS_STATE_EXECUTION ||
883 tis->loc[locty].state == TPM_TIS_STATE_COMPLETION) {
884 /* drop the byte */
885 } else {
886 DPRINTF("tpm_tis: Data to send to TPM: %08x (size=%d)\n",
887 (int)val, size);
888 if (tis->loc[locty].state == TPM_TIS_STATE_READY) {
889 tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;
890 tpm_tis_sts_set(&tis->loc[locty],
891 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
894 val >>= shift;
895 if (size > 4 - (addr & 0x3)) {
896 /* prevent access beyond FIFO */
897 size = 4 - (addr & 0x3);
900 while ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {
901 if (tis->loc[locty].w_offset < tis->loc[locty].w_buffer.size) {
902 tis->loc[locty].w_buffer.
903 buffer[tis->loc[locty].w_offset++] = (uint8_t)val;
904 val >>= 8;
905 size--;
906 } else {
907 tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_VALID);
911 /* check for complete packet */
912 if (tis->loc[locty].w_offset > 5 &&
913 (tis->loc[locty].sts & TPM_TIS_STS_EXPECT)) {
914 /* we have a packet length - see if we have all of it */
915 #ifdef RAISE_STS_IRQ
916 bool need_irq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);
917 #endif
918 len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
919 if (len > tis->loc[locty].w_offset) {
920 tpm_tis_sts_set(&tis->loc[locty],
921 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
922 } else {
923 /* packet complete */
924 tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_VALID);
926 #ifdef RAISE_STS_IRQ
927 if (need_irq) {
928 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
930 #endif
933 break;
934 case TPM_TIS_REG_INTERFACE_ID:
935 if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) {
936 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
937 tis->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK;
940 break;
944 static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
945 uint64_t val, unsigned size)
947 tpm_tis_mmio_write_intern(opaque, addr, val, size, false);
950 static const MemoryRegionOps tpm_tis_memory_ops = {
951 .read = tpm_tis_mmio_read,
952 .write = tpm_tis_mmio_write,
953 .endianness = DEVICE_LITTLE_ENDIAN,
954 .valid = {
955 .min_access_size = 1,
956 .max_access_size = 4,
960 static int tpm_tis_do_startup_tpm(TPMState *s)
962 return tpm_backend_startup_tpm(s->be_driver);
966 * Get the TPMVersion of the backend device being used
968 TPMVersion tpm_tis_get_tpm_version(Object *obj)
970 TPMState *s = TPM(obj);
972 return tpm_backend_get_tpm_version(s->be_driver);
976 * This function is called when the machine starts, resets or due to
977 * S3 resume.
979 static void tpm_tis_reset(DeviceState *dev)
981 TPMState *s = TPM(dev);
982 TPMTISEmuState *tis = &s->s.tis;
983 int c;
985 s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
987 tpm_backend_reset(s->be_driver);
989 tis->active_locty = TPM_TIS_NO_LOCALITY;
990 tis->next_locty = TPM_TIS_NO_LOCALITY;
991 tis->aborting_locty = TPM_TIS_NO_LOCALITY;
993 for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
994 tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
995 switch (s->be_tpm_version) {
996 case TPM_VERSION_UNSPEC:
997 break;
998 case TPM_VERSION_1_2:
999 tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2;
1000 tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3;
1001 break;
1002 case TPM_VERSION_2_0:
1003 tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0;
1004 tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0;
1005 break;
1007 tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
1008 tis->loc[c].ints = 0;
1009 tis->loc[c].state = TPM_TIS_STATE_IDLE;
1011 tis->loc[c].w_offset = 0;
1012 tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer);
1013 tis->loc[c].r_offset = 0;
1014 tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer);
1017 tpm_tis_do_startup_tpm(s);
1020 static const VMStateDescription vmstate_tpm_tis = {
1021 .name = "tpm",
1022 .unmigratable = 1,
1025 static Property tpm_tis_properties[] = {
1026 DEFINE_PROP_UINT32("irq", TPMState,
1027 s.tis.irq_num, TPM_TIS_IRQ),
1028 DEFINE_PROP_STRING("tpmdev", TPMState, backend),
1029 DEFINE_PROP_END_OF_LIST(),
1032 static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
1034 TPMState *s = TPM(dev);
1035 TPMTISEmuState *tis = &s->s.tis;
1037 s->be_driver = qemu_find_tpm(s->backend);
1038 if (!s->be_driver) {
1039 error_setg(errp, "tpm_tis: backend driver with id %s could not be "
1040 "found", s->backend);
1041 return;
1044 s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
1046 if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
1047 error_setg(errp, "tpm_tis: backend driver with id %s could not be "
1048 "initialized", s->backend);
1049 return;
1052 if (tis->irq_num > 15) {
1053 error_setg(errp, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
1054 "of 0 to 15", tis->irq_num);
1055 return;
1058 tis->bh = qemu_bh_new(tpm_tis_receive_bh, s);
1060 isa_init_irq(&s->busdev, &tis->irq, tis->irq_num);
1062 memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
1063 TPM_TIS_ADDR_BASE, &s->mmio);
1066 static void tpm_tis_initfn(Object *obj)
1068 TPMState *s = TPM(obj);
1070 memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
1071 s, "tpm-tis-mmio",
1072 TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
1075 static void tpm_tis_class_init(ObjectClass *klass, void *data)
1077 DeviceClass *dc = DEVICE_CLASS(klass);
1079 dc->realize = tpm_tis_realizefn;
1080 dc->props = tpm_tis_properties;
1081 dc->reset = tpm_tis_reset;
1082 dc->vmsd = &vmstate_tpm_tis;
1085 static const TypeInfo tpm_tis_info = {
1086 .name = TYPE_TPM_TIS,
1087 .parent = TYPE_ISA_DEVICE,
1088 .instance_size = sizeof(TPMState),
1089 .instance_init = tpm_tis_initfn,
1090 .class_init = tpm_tis_class_init,
1093 static void tpm_tis_register(void)
1095 type_register_static(&tpm_tis_info);
1096 tpm_register_model(TPM_MODEL_TPM_TIS);
1099 type_init(tpm_tis_register)