]> git.proxmox.com Git - mirror_qemu.git/blame - hw/tpm/tpm_tis.c
tpm: avoid clang shifting negative signed warning
[mirror_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
dccfcd0e 25#include "sysemu/tpm_backend.h"
edff8678 26#include "tpm_int.h"
4be74634 27#include "sysemu/block-backend.h"
edff8678
SB
28#include "exec/address-spaces.h"
29#include "hw/hw.h"
0d09e41a 30#include "hw/i386/pc.h"
edff8678 31#include "hw/pci/pci_ids.h"
bdee56f5 32#include "tpm_tis.h"
edff8678 33#include "qemu-common.h"
6a1751b7 34#include "qemu/main-loop.h"
5cb18b3d 35#include "sysemu/tpm_backend.h"
edff8678 36
4d1ba9c4 37#define DEBUG_TIS 0
edff8678 38
4d1ba9c4
SB
39#define DPRINTF(fmt, ...) do { \
40 if (DEBUG_TIS) { \
41 printf(fmt, ## __VA_ARGS__); \
42 } \
43} while (0);
edff8678
SB
44
45/* whether the STS interrupt is supported */
46#define RAISE_STS_IRQ
47
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
116694c3 56#define TPM_TIS_REG_INTERFACE_ID 0x30
2eae8c75
SB
57#define TPM_TIS_REG_DATA_XFIFO 0x80
58#define TPM_TIS_REG_DATA_XFIFO_END 0xbc
edff8678
SB
59#define TPM_TIS_REG_DID_VID 0xf00
60#define TPM_TIS_REG_RID 0xf04
61
8db7c415
SB
62/* vendor-specific registers */
63#define TPM_TIS_REG_DEBUG 0xf90
64
116694c3
SB
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 */
70
edff8678
SB
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)
fd859081 76#define TPM_TIS_STS_SELFTEST_DONE (1 << 2)
edff8678
SB
77#define TPM_TIS_STS_RESPONSE_RETRY (1 << 1)
78
79#define TPM_TIS_BURST_COUNT_SHIFT 8
80#define TPM_TIS_BURST_COUNT(X) \
81 ((X) << TPM_TIS_BURST_COUNT_SHIFT)
82
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)
90
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)
96
97#define TPM_TIS_INT_POLARITY_MASK (3 << 3)
98#define TPM_TIS_INT_POLARITY_LOW_LEVEL (1 << 3)
99
100#ifndef RAISE_STS_IRQ
101
102#define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
103 TPM_TIS_INT_DATA_AVAILABLE | \
104 TPM_TIS_INT_COMMAND_READY)
105
106#else
107
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)
112
113#endif
114
9dd5c40d 115#define TPM_TIS_CAP_INTERFACE_VERSION1_3 (2 << 28)
116694c3 116#define TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 (3 << 28)
9dd5c40d
SB
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)
edff8678 120#define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */
116694c3
SB
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)
127
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)
134
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 */
141
142#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3 \
143 (TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 | \
886ce6f8 144 (~0u << 4)/* all of it is don't care */)
116694c3
SB
145
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)
edff8678
SB
152
153#define TPM_TIS_TPM_DID 0x0001
154#define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM
155#define TPM_TIS_TPM_RID 0x0001
156
157#define TPM_TIS_NO_DATA_BYTE 0xff
158
8db7c415
SB
159/* local prototypes */
160
161static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
162 unsigned size);
163
edff8678
SB
164/* utility functions */
165
166static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
167{
168 return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
169}
170
171static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer *sb)
172{
173 return be32_to_cpu(*(uint32_t *)&sb->buffer[2]);
174}
175
176static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
177{
178#ifdef DEBUG_TIS
179 uint32_t len, i;
180
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");
186 }
187 DPRINTF("%.2X ", sb->buffer[i]);
188 }
189 DPRINTF("\n");
190#endif
191}
192
fd859081
SB
193/*
194 * Set the given flags in the STS register by clearing the register but
116694c3
SB
195 * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting
196 * the new flags.
fd859081
SB
197 *
198 * The SELFTEST_DONE flag is acquired from the backend that determines it by
199 * peeking into TPM commands.
200 *
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.
205 */
206static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
207{
116694c3 208 l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK;
fd859081
SB
209 l->sts |= flags;
210}
211
edff8678
SB
212/*
213 * Send a request to the TPM.
214 */
215static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
216{
217 TPMTISEmuState *tis = &s->s.tis;
218
219 tpm_tis_show_buffer(&tis->loc[locty].w_buffer, "tpm_tis: To TPM");
220
221 s->locty_number = locty;
222 s->locty_data = &tis->loc[locty];
223
224 /*
225 * w_offset serves as length indicator for length of data;
226 * it's reset when the response comes back
227 */
228 tis->loc[locty].state = TPM_TIS_STATE_EXECUTION;
229
8f0605cc 230 tpm_backend_deliver_request(s->be_driver);
edff8678
SB
231}
232
233/* raise an interrupt if allowed */
234static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
235{
236 TPMTISEmuState *tis = &s->s.tis;
237
238 if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
239 return;
240 }
241
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;
247 }
248}
249
250static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
251{
252 uint8_t l;
253
254 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
255 if (l == locty) {
256 continue;
257 }
258 if ((s->s.tis.loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
259 return 1;
260 }
261 }
262
263 return 0;
264}
265
266static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
267{
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;
272
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;
276
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);
282 }
283 /* reset flags on the old active locality */
284 tis->loc[s->s.tis.active_locty].access &= mask;
285
286 if (is_seize) {
287 tis->loc[tis->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
288 }
289 }
290
291 tis->active_locty = new_active_locty;
292
293 DPRINTF("tpm_tis: Active locality is now %d\n", s->s.tis.active_locty);
294
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);
300 }
301
302 if (change) {
303 tpm_tis_raise_irq(s, tis->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
304 }
305}
306
307/* abort -- this function switches the locality */
308static void tpm_tis_abort(TPMState *s, uint8_t locty)
309{
310 TPMTISEmuState *tis = &s->s.tis;
311
312 tis->loc[locty].r_offset = 0;
313 tis->loc[locty].w_offset = 0;
314
315 DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis->next_locty);
316
317 /*
318 * Need to react differently depending on who's aborting now and
319 * which locality will become active afterwards.
320 */
321 if (tis->aborting_locty == tis->next_locty) {
322 tis->loc[tis->aborting_locty].state = TPM_TIS_STATE_READY;
fd859081
SB
323 tpm_tis_sts_set(&tis->loc[tis->aborting_locty],
324 TPM_TIS_STS_COMMAND_READY);
edff8678
SB
325 tpm_tis_raise_irq(s, tis->aborting_locty, TPM_TIS_INT_COMMAND_READY);
326 }
327
328 /* locality after abort is another one than the current one */
329 tpm_tis_new_active_locality(s, tis->next_locty);
330
331 tis->next_locty = TPM_TIS_NO_LOCALITY;
332 /* nobody's aborting a command anymore */
333 tis->aborting_locty = TPM_TIS_NO_LOCALITY;
334}
335
336/* prepare aborting current command */
337static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
338{
339 TPMTISEmuState *tis = &s->s.tis;
340 uint8_t busy_locty;
341
342 tis->aborting_locty = locty;
343 tis->next_locty = newlocty; /* locality after successful abort */
344
345 /*
346 * only abort a command using an interrupt if currently executing
347 * a command AND if there's a valid connection to the vTPM.
348 */
349 for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
350 if (tis->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
351 /*
352 * request the backend to cancel. Some backends may not
353 * support it
354 */
8f0605cc 355 tpm_backend_cancel_cmd(s->be_driver);
edff8678
SB
356 return;
357 }
358 }
359
360 tpm_tis_abort(s, locty);
361}
362
363static void tpm_tis_receive_bh(void *opaque)
364{
365 TPMState *s = opaque;
366 TPMTISEmuState *tis = &s->s.tis;
367 uint8_t locty = s->locty_number;
368
fd859081
SB
369 tpm_tis_sts_set(&tis->loc[locty],
370 TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
edff8678
SB
371 tis->loc[locty].state = TPM_TIS_STATE_COMPLETION;
372 tis->loc[locty].r_offset = 0;
373 tis->loc[locty].w_offset = 0;
374
375 if (TPM_TIS_IS_VALID_LOCTY(tis->next_locty)) {
376 tpm_tis_abort(s, locty);
377 }
378
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
385}
386
387/*
388 * Callback from the TPM to indicate that the response was received.
389 */
fd859081
SB
390static void tpm_tis_receive_cb(TPMState *s, uint8_t locty,
391 bool is_selftest_done)
edff8678
SB
392{
393 TPMTISEmuState *tis = &s->s.tis;
fd859081 394 uint8_t l;
edff8678
SB
395
396 assert(s->locty_number == locty);
397
fd859081
SB
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;
401 }
402 }
403
edff8678
SB
404 qemu_bh_schedule(tis->bh);
405}
406
407/*
408 * Read a byte of response data
409 */
410static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
411{
412 TPMTISEmuState *tis = &s->s.tis;
413 uint32_t ret = TPM_TIS_NO_DATA_BYTE;
414 uint16_t len;
415
416 if ((tis->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
417 len = tpm_tis_get_size_from_buffer(&tis->loc[locty].r_buffer);
418
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 */
fd859081 422 tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_VALID);
edff8678
SB
423#ifdef RAISE_STS_IRQ
424 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
425#endif
426 }
427 DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x [%d]\n",
428 ret, tis->loc[locty].r_offset-1);
429 }
430
431 return ret;
432}
433
8db7c415
SB
434#ifdef DEBUG_TIS
435static void tpm_tis_dump_state(void *opaque, hwaddr addr)
436{
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;
452
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);
458
459 for (idx = 0; regs[idx] != 0xfff; idx++) {
460 DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs[idx],
070c7607 461 (int)tpm_tis_mmio_read(opaque, base + regs[idx], 4));
8db7c415
SB
462 }
463
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: " : "");
474 }
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: " : "");
486 }
487 DPRINTF("\n");
488}
489#endif
490
edff8678
SB
491/*
492 * Read a register of the TIS interface
493 * See specs pages 33-63 for description of the registers
494 */
495static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
496 unsigned size)
497{
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;
feeb755f 505 uint8_t v;
edff8678 506
8f0605cc 507 if (tpm_backend_had_startup_error(s->be_driver)) {
edff8678
SB
508 return val;
509 }
510
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;
518 }
8f0605cc 519 val |= !tpm_backend_get_tpm_established_flag(s->be_driver);
edff8678
SB
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:
116694c3
SB
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;
541 }
edff8678
SB
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;
552 /*
553 * byte-sized reads should not return 0x00 for 0x100
554 * available bytes.
555 */
556 if (size == 1 && avail > 0xff) {
557 avail = 0xff;
558 }
559 val = TPM_TIS_BURST_COUNT(avail) | tis->loc[locty].sts;
560 }
561 }
562 break;
563 case TPM_TIS_REG_DATA_FIFO:
2eae8c75 564 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
edff8678 565 if (tis->active_locty == locty) {
feeb755f
SB
566 if (size > 4 - (addr & 0x3)) {
567 /* prevent access beyond FIFO */
568 size = 4 - (addr & 0x3);
569 }
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;
580 }
581 val |= (v << shift);
582 shift += 8;
583 size--;
edff8678 584 }
feeb755f 585 shift = 0; /* no more adjustments */
edff8678
SB
586 }
587 break;
116694c3
SB
588 case TPM_TIS_REG_INTERFACE_ID:
589 val = tis->loc[locty].iface_id;
590 break;
edff8678
SB
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;
8db7c415
SB
597#ifdef DEBUG_TIS
598 case TPM_TIS_REG_DEBUG:
599 tpm_tis_dump_state(opaque, addr);
600 break;
601#endif
edff8678
SB
602 }
603
604 if (shift) {
605 val >>= shift;
606 }
607
070c7607 608 DPRINTF("tpm_tis: read.%u(%08x) = %08x\n", size, (int)addr, (int)val);
edff8678
SB
609
610 return val;
611}
612
613/*
614 * Write a value to a register of the TIS interface
615 * See specs pages 33-63 for description of the registers
616 */
617static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
618 uint64_t val, unsigned size,
619 bool hw_access)
620{
621 TPMState *s = opaque;
622 TPMTISEmuState *tis = &s->s.tis;
feeb755f
SB
623 uint16_t off = addr & 0xffc;
624 uint8_t shift = (addr & 0x3) * 8;
edff8678
SB
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;
feeb755f 629 uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0);
edff8678 630
070c7607 631 DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size, (int)addr, (int)val);
edff8678
SB
632
633 if (locty == 4 && !hw_access) {
634 DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
635 return;
636 }
637
8f0605cc 638 if (tpm_backend_had_startup_error(s->be_driver)) {
edff8678
SB
639 return;
640 }
641
feeb755f
SB
642 val &= mask;
643
644 if (shift) {
645 val <<= shift;
646 mask <<= shift;
647 }
648
649 mask ^= 0xffffffff;
650
edff8678
SB
651 switch (off) {
652 case TPM_TIS_REG_ACCESS:
653
654 if ((val & TPM_TIS_ACCESS_SEIZE)) {
655 val &= ~(TPM_TIS_ACCESS_REQUEST_USE |
656 TPM_TIS_ACCESS_ACTIVE_LOCALITY);
657 }
658
659 active_locty = tis->active_locty;
660
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);
665
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;
673 }
674 }
675 DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
676 "Next active locality: %d\n",
677 newlocty);
678
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;
684 }
685 } else {
686 /* not currently the owner; clear a pending request */
687 tis->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE;
688 }
689 }
690
691 if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) {
692 tis->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED;
693 }
694
695 if ((val & TPM_TIS_ACCESS_SEIZE)) {
696 /*
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
702 */
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;
707
708 /* already a pending SEIZE ? */
709 if ((tis->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) {
710 break;
711 }
712
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;
718 }
719 }
720
721 if (higher_seize) {
722 break;
723 }
724
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;
728 }
729
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;
738 }
739 }
740
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;
748 }
749 }
750 }
751
752 if (set_new_locty) {
753 tpm_tis_new_active_locality(s, active_locty);
754 }
755
756 break;
757 case TPM_TIS_REG_INT_ENABLE:
758 if (tis->active_locty != locty) {
759 break;
760 }
761
feeb755f
SB
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));
edff8678
SB
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;
773 }
774
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");
782 }
783 }
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;
789 }
790
116694c3
SB
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) {
795 /*
796 * request the backend to cancel. Some backends may not
797 * support it
798 */
799 tpm_backend_cancel_cmd(s->be_driver);
800 }
801 }
802
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);
806 }
807 }
808 }
809
edff8678
SB
810 val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
811 TPM_TIS_STS_RESPONSE_RETRY);
812
813 if (val == TPM_TIS_STS_COMMAND_READY) {
814 switch (tis->loc[locty].state) {
815
816 case TPM_TIS_STATE_READY:
817 tis->loc[locty].w_offset = 0;
818 tis->loc[locty].r_offset = 0;
819 break;
820
821 case TPM_TIS_STATE_IDLE:
fd859081 822 tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_COMMAND_READY);
edff8678
SB
823 tis->loc[locty].state = TPM_TIS_STATE_READY;
824 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
825 break;
826
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;
834
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)) {
fd859081
SB
841 tpm_tis_sts_set(&tis->loc[locty],
842 TPM_TIS_STS_COMMAND_READY);
edff8678
SB
843 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY);
844 }
845 tis->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE);
846 break;
847
848 }
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);
854 }
855 break;
856 default:
857 /* ignore */
858 break;
859 }
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;
fd859081
SB
864 tpm_tis_sts_set(&tis->loc[locty],
865 TPM_TIS_STS_VALID|
866 TPM_TIS_STS_DATA_AVAILABLE);
edff8678
SB
867 break;
868 default:
869 /* ignore */
870 break;
871 }
872 }
873 break;
874 case TPM_TIS_REG_DATA_FIFO:
2eae8c75 875 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END:
edff8678
SB
876 /* data fifo */
877 if (tis->active_locty != locty) {
878 break;
879 }
880
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 {
feeb755f 886 DPRINTF("tpm_tis: Data to send to TPM: %08x (size=%d)\n",
070c7607 887 (int)val, size);
edff8678
SB
888 if (tis->loc[locty].state == TPM_TIS_STATE_READY) {
889 tis->loc[locty].state = TPM_TIS_STATE_RECEPTION;
fd859081
SB
890 tpm_tis_sts_set(&tis->loc[locty],
891 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
edff8678
SB
892 }
893
feeb755f
SB
894 val >>= shift;
895 if (size > 4 - (addr & 0x3)) {
896 /* prevent access beyond FIFO */
897 size = 4 - (addr & 0x3);
898 }
899
900 while ((tis->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) {
edff8678
SB
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;
feeb755f
SB
904 val >>= 8;
905 size--;
edff8678 906 } else {
fd859081 907 tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_VALID);
edff8678
SB
908 }
909 }
910
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
29b558d8 916 bool need_irq = !(tis->loc[locty].sts & TPM_TIS_STS_VALID);
edff8678
SB
917#endif
918 len = tpm_tis_get_size_from_buffer(&tis->loc[locty].w_buffer);
919 if (len > tis->loc[locty].w_offset) {
fd859081
SB
920 tpm_tis_sts_set(&tis->loc[locty],
921 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID);
edff8678
SB
922 } else {
923 /* packet complete */
fd859081 924 tpm_tis_sts_set(&tis->loc[locty], TPM_TIS_STS_VALID);
edff8678
SB
925 }
926#ifdef RAISE_STS_IRQ
29b558d8 927 if (need_irq) {
edff8678
SB
928 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
929 }
930#endif
931 }
932 }
933 break;
116694c3
SB
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;
938 }
939 }
940 break;
edff8678
SB
941 }
942}
943
944static void tpm_tis_mmio_write(void *opaque, hwaddr addr,
945 uint64_t val, unsigned size)
946{
e7ae771f 947 tpm_tis_mmio_write_intern(opaque, addr, val, size, false);
edff8678
SB
948}
949
950static 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,
957 },
958};
959
960static int tpm_tis_do_startup_tpm(TPMState *s)
961{
8f0605cc 962 return tpm_backend_startup_tpm(s->be_driver);
edff8678
SB
963}
964
5cb18b3d
SB
965/*
966 * Get the TPMVersion of the backend device being used
967 */
968TPMVersion tpm_tis_get_tpm_version(Object *obj)
969{
970 TPMState *s = TPM(obj);
971
972 return tpm_backend_get_tpm_version(s->be_driver);
973}
974
edff8678
SB
975/*
976 * This function is called when the machine starts, resets or due to
977 * S3 resume.
978 */
979static void tpm_tis_reset(DeviceState *dev)
980{
981 TPMState *s = TPM(dev);
982 TPMTISEmuState *tis = &s->s.tis;
983 int c;
984
116694c3
SB
985 s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
986
8f0605cc 987 tpm_backend_reset(s->be_driver);
edff8678
SB
988
989 tis->active_locty = TPM_TIS_NO_LOCALITY;
990 tis->next_locty = TPM_TIS_NO_LOCALITY;
991 tis->aborting_locty = TPM_TIS_NO_LOCALITY;
992
993 for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
994 tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
116694c3
SB
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;
1006 }
edff8678
SB
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;
1010
1011 tis->loc[c].w_offset = 0;
8f0605cc 1012 tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].w_buffer);
edff8678 1013 tis->loc[c].r_offset = 0;
8f0605cc 1014 tpm_backend_realloc_buffer(s->be_driver, &tis->loc[c].r_buffer);
edff8678
SB
1015 }
1016
1017 tpm_tis_do_startup_tpm(s);
1018}
1019
1020static const VMStateDescription vmstate_tpm_tis = {
1021 .name = "tpm",
1022 .unmigratable = 1,
1023};
1024
1025static 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(),
1030};
1031
1032static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
1033{
1034 TPMState *s = TPM(dev);
1035 TPMTISEmuState *tis = &s->s.tis;
1036
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;
1042 }
1043
1044 s->be_driver->fe_model = TPM_MODEL_TPM_TIS;
1045
8f0605cc 1046 if (tpm_backend_init(s->be_driver, s, tpm_tis_receive_cb)) {
edff8678
SB
1047 error_setg(errp, "tpm_tis: backend driver with id %s could not be "
1048 "initialized", s->backend);
1049 return;
1050 }
1051
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.\n", tis->irq_num);
1055 return;
1056 }
1057
1058 tis->bh = qemu_bh_new(tpm_tis_receive_bh, s);
1059
1060 isa_init_irq(&s->busdev, &tis->irq, tis->irq_num);
9dfd24ed
SB
1061
1062 memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
1063 TPM_TIS_ADDR_BASE, &s->mmio);
edff8678
SB
1064}
1065
1066static void tpm_tis_initfn(Object *obj)
1067{
edff8678
SB
1068 TPMState *s = TPM(obj);
1069
853dca12
PB
1070 memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
1071 s, "tpm-tis-mmio",
edff8678 1072 TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
edff8678
SB
1073}
1074
edff8678
SB
1075static void tpm_tis_class_init(ObjectClass *klass, void *data)
1076{
1077 DeviceClass *dc = DEVICE_CLASS(klass);
1078
1079 dc->realize = tpm_tis_realizefn;
1080 dc->props = tpm_tis_properties;
1081 dc->reset = tpm_tis_reset;
1082 dc->vmsd = &vmstate_tpm_tis;
1083}
1084
1085static 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,
edff8678
SB
1090 .class_init = tpm_tis_class_init,
1091};
1092
1093static void tpm_tis_register(void)
1094{
1095 type_register_static(&tpm_tis_info);
1096 tpm_register_model(TPM_MODEL_TPM_TIS);
1097}
1098
1099type_init(tpm_tis_register)