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