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