2 * tpm_tis.c - QEMU's TPM TIS interface emulator
4 * Copyright (C) 2006,2010-2013 IBM Corporation
7 * Stefan Berger <stefanb@us.ibm.com>
8 * David Safford <safford@us.ibm.com>
10 * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
12 * This work is licensed under the terms of the GNU GPL, version 2 or later.
13 * See the COPYING file in the top-level directory.
15 * Implementation of the TIS interface according to specs found at
16 * http://www.trustedcomputinggroup.org. This implementation currently
17 * supports version 1.21, revision 1.0.
18 * In the developers menu choose the PC Client section then find the TIS
23 #include "block/block.h"
24 #include "exec/address-spaces.h"
27 #include "hw/pci/pci_ids.h"
28 #include "tpm/tpm_tis.h"
29 #include "qemu-common.h"
31 /*#define DEBUG_TIS */
34 #define DPRINTF(fmt, ...) \
35 do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0)
37 #define DPRINTF(fmt, ...) \
41 /* whether the STS interrupt is supported */
45 #define TPM_TIS_REG_ACCESS 0x00
46 #define TPM_TIS_REG_INT_ENABLE 0x08
47 #define TPM_TIS_REG_INT_VECTOR 0x0c
48 #define TPM_TIS_REG_INT_STATUS 0x10
49 #define TPM_TIS_REG_INTF_CAPABILITY 0x14
50 #define TPM_TIS_REG_STS 0x18
51 #define TPM_TIS_REG_DATA_FIFO 0x24
52 #define TPM_TIS_REG_DID_VID 0xf00
53 #define TPM_TIS_REG_RID 0xf04
55 /* vendor-specific registers */
56 #define TPM_TIS_REG_DEBUG 0xf90
58 #define TPM_TIS_STS_VALID (1 << 7)
59 #define TPM_TIS_STS_COMMAND_READY (1 << 6)
60 #define TPM_TIS_STS_TPM_GO (1 << 5)
61 #define TPM_TIS_STS_DATA_AVAILABLE (1 << 4)
62 #define TPM_TIS_STS_EXPECT (1 << 3)
63 #define TPM_TIS_STS_RESPONSE_RETRY (1 << 1)
65 #define TPM_TIS_BURST_COUNT_SHIFT 8
66 #define TPM_TIS_BURST_COUNT(X) \
67 ((X) << TPM_TIS_BURST_COUNT_SHIFT)
69 #define TPM_TIS_ACCESS_TPM_REG_VALID_STS (1 << 7)
70 #define TPM_TIS_ACCESS_ACTIVE_LOCALITY (1 << 5)
71 #define TPM_TIS_ACCESS_BEEN_SEIZED (1 << 4)
72 #define TPM_TIS_ACCESS_SEIZE (1 << 3)
73 #define TPM_TIS_ACCESS_PENDING_REQUEST (1 << 2)
74 #define TPM_TIS_ACCESS_REQUEST_USE (1 << 1)
75 #define TPM_TIS_ACCESS_TPM_ESTABLISHMENT (1 << 0)
77 #define TPM_TIS_INT_ENABLED (1 << 31)
78 #define TPM_TIS_INT_DATA_AVAILABLE (1 << 0)
79 #define TPM_TIS_INT_STS_VALID (1 << 1)
80 #define TPM_TIS_INT_LOCALITY_CHANGED (1 << 2)
81 #define TPM_TIS_INT_COMMAND_READY (1 << 7)
83 #define TPM_TIS_INT_POLARITY_MASK (3 << 3)
84 #define TPM_TIS_INT_POLARITY_LOW_LEVEL (1 << 3)
88 #define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
89 TPM_TIS_INT_DATA_AVAILABLE | \
90 TPM_TIS_INT_COMMAND_READY)
94 #define TPM_TIS_INTERRUPTS_SUPPORTED (TPM_TIS_INT_LOCALITY_CHANGED | \
95 TPM_TIS_INT_DATA_AVAILABLE | \
96 TPM_TIS_INT_STS_VALID | \
97 TPM_TIS_INT_COMMAND_READY)
101 #define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL (1 << 4) /* support is mandatory */
102 #define TPM_TIS_CAPABILITIES_SUPPORTED (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
103 TPM_TIS_INTERRUPTS_SUPPORTED)
105 #define TPM_TIS_TPM_DID 0x0001
106 #define TPM_TIS_TPM_VID PCI_VENDOR_ID_IBM
107 #define TPM_TIS_TPM_RID 0x0001
109 #define TPM_TIS_NO_DATA_BYTE 0xff
111 /* local prototypes */
113 static uint64_t tpm_tis_mmio_read(void *opaque
, hwaddr addr
,
116 /* utility functions */
118 static uint8_t tpm_tis_locality_from_addr(hwaddr addr
)
120 return (uint8_t)((addr
>> TPM_TIS_LOCALITY_SHIFT
) & 0x7);
123 static uint32_t tpm_tis_get_size_from_buffer(const TPMSizedBuffer
*sb
)
125 return be32_to_cpu(*(uint32_t *)&sb
->buffer
[2]);
128 static void tpm_tis_show_buffer(const TPMSizedBuffer
*sb
, const char *string
)
133 len
= tpm_tis_get_size_from_buffer(sb
);
134 DPRINTF("tpm_tis: %s length = %d\n", string
, len
);
135 for (i
= 0; i
< len
; i
++) {
136 if (i
&& !(i
% 16)) {
139 DPRINTF("%.2X ", sb
->buffer
[i
]);
146 * Send a request to the TPM.
148 static void tpm_tis_tpm_send(TPMState
*s
, uint8_t locty
)
150 TPMTISEmuState
*tis
= &s
->s
.tis
;
152 tpm_tis_show_buffer(&tis
->loc
[locty
].w_buffer
, "tpm_tis: To TPM");
154 s
->locty_number
= locty
;
155 s
->locty_data
= &tis
->loc
[locty
];
158 * w_offset serves as length indicator for length of data;
159 * it's reset when the response comes back
161 tis
->loc
[locty
].state
= TPM_TIS_STATE_EXECUTION
;
163 s
->be_driver
->ops
->deliver_request(s
->be_driver
);
166 /* raise an interrupt if allowed */
167 static void tpm_tis_raise_irq(TPMState
*s
, uint8_t locty
, uint32_t irqmask
)
169 TPMTISEmuState
*tis
= &s
->s
.tis
;
171 if (!TPM_TIS_IS_VALID_LOCTY(locty
)) {
175 if ((tis
->loc
[locty
].inte
& TPM_TIS_INT_ENABLED
) &&
176 (tis
->loc
[locty
].inte
& irqmask
)) {
177 DPRINTF("tpm_tis: Raising IRQ for flag %08x\n", irqmask
);
178 qemu_irq_raise(s
->s
.tis
.irq
);
179 tis
->loc
[locty
].ints
|= irqmask
;
183 static uint32_t tpm_tis_check_request_use_except(TPMState
*s
, uint8_t locty
)
187 for (l
= 0; l
< TPM_TIS_NUM_LOCALITIES
; l
++) {
191 if ((s
->s
.tis
.loc
[l
].access
& TPM_TIS_ACCESS_REQUEST_USE
)) {
199 static void tpm_tis_new_active_locality(TPMState
*s
, uint8_t new_active_locty
)
201 TPMTISEmuState
*tis
= &s
->s
.tis
;
202 bool change
= (s
->s
.tis
.active_locty
!= new_active_locty
);
206 if (change
&& TPM_TIS_IS_VALID_LOCTY(s
->s
.tis
.active_locty
)) {
207 is_seize
= TPM_TIS_IS_VALID_LOCTY(new_active_locty
) &&
208 tis
->loc
[new_active_locty
].access
& TPM_TIS_ACCESS_SEIZE
;
211 mask
= ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY
);
213 mask
= ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY
|
214 TPM_TIS_ACCESS_REQUEST_USE
);
216 /* reset flags on the old active locality */
217 tis
->loc
[s
->s
.tis
.active_locty
].access
&= mask
;
220 tis
->loc
[tis
->active_locty
].access
|= TPM_TIS_ACCESS_BEEN_SEIZED
;
224 tis
->active_locty
= new_active_locty
;
226 DPRINTF("tpm_tis: Active locality is now %d\n", s
->s
.tis
.active_locty
);
228 if (TPM_TIS_IS_VALID_LOCTY(new_active_locty
)) {
229 /* set flags on the new active locality */
230 tis
->loc
[new_active_locty
].access
|= TPM_TIS_ACCESS_ACTIVE_LOCALITY
;
231 tis
->loc
[new_active_locty
].access
&= ~(TPM_TIS_ACCESS_REQUEST_USE
|
232 TPM_TIS_ACCESS_SEIZE
);
236 tpm_tis_raise_irq(s
, tis
->active_locty
, TPM_TIS_INT_LOCALITY_CHANGED
);
240 /* abort -- this function switches the locality */
241 static void tpm_tis_abort(TPMState
*s
, uint8_t locty
)
243 TPMTISEmuState
*tis
= &s
->s
.tis
;
245 tis
->loc
[locty
].r_offset
= 0;
246 tis
->loc
[locty
].w_offset
= 0;
248 DPRINTF("tpm_tis: tis_abort: new active locality is %d\n", tis
->next_locty
);
251 * Need to react differently depending on who's aborting now and
252 * which locality will become active afterwards.
254 if (tis
->aborting_locty
== tis
->next_locty
) {
255 tis
->loc
[tis
->aborting_locty
].state
= TPM_TIS_STATE_READY
;
256 tis
->loc
[tis
->aborting_locty
].sts
= TPM_TIS_STS_COMMAND_READY
;
257 tpm_tis_raise_irq(s
, tis
->aborting_locty
, TPM_TIS_INT_COMMAND_READY
);
260 /* locality after abort is another one than the current one */
261 tpm_tis_new_active_locality(s
, tis
->next_locty
);
263 tis
->next_locty
= TPM_TIS_NO_LOCALITY
;
264 /* nobody's aborting a command anymore */
265 tis
->aborting_locty
= TPM_TIS_NO_LOCALITY
;
268 /* prepare aborting current command */
269 static void tpm_tis_prep_abort(TPMState
*s
, uint8_t locty
, uint8_t newlocty
)
271 TPMTISEmuState
*tis
= &s
->s
.tis
;
274 tis
->aborting_locty
= locty
;
275 tis
->next_locty
= newlocty
; /* locality after successful abort */
278 * only abort a command using an interrupt if currently executing
279 * a command AND if there's a valid connection to the vTPM.
281 for (busy_locty
= 0; busy_locty
< TPM_TIS_NUM_LOCALITIES
; busy_locty
++) {
282 if (tis
->loc
[busy_locty
].state
== TPM_TIS_STATE_EXECUTION
) {
284 * request the backend to cancel. Some backends may not
287 s
->be_driver
->ops
->cancel_cmd(s
->be_driver
);
292 tpm_tis_abort(s
, locty
);
295 static void tpm_tis_receive_bh(void *opaque
)
297 TPMState
*s
= opaque
;
298 TPMTISEmuState
*tis
= &s
->s
.tis
;
299 uint8_t locty
= s
->locty_number
;
301 tis
->loc
[locty
].sts
= TPM_TIS_STS_VALID
| TPM_TIS_STS_DATA_AVAILABLE
;
302 tis
->loc
[locty
].state
= TPM_TIS_STATE_COMPLETION
;
303 tis
->loc
[locty
].r_offset
= 0;
304 tis
->loc
[locty
].w_offset
= 0;
306 if (TPM_TIS_IS_VALID_LOCTY(tis
->next_locty
)) {
307 tpm_tis_abort(s
, locty
);
310 #ifndef RAISE_STS_IRQ
311 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_DATA_AVAILABLE
);
313 tpm_tis_raise_irq(s
, locty
,
314 TPM_TIS_INT_DATA_AVAILABLE
| TPM_TIS_INT_STS_VALID
);
319 * Callback from the TPM to indicate that the response was received.
321 static void tpm_tis_receive_cb(TPMState
*s
, uint8_t locty
)
323 TPMTISEmuState
*tis
= &s
->s
.tis
;
325 assert(s
->locty_number
== locty
);
327 qemu_bh_schedule(tis
->bh
);
331 * Read a byte of response data
333 static uint32_t tpm_tis_data_read(TPMState
*s
, uint8_t locty
)
335 TPMTISEmuState
*tis
= &s
->s
.tis
;
336 uint32_t ret
= TPM_TIS_NO_DATA_BYTE
;
339 if ((tis
->loc
[locty
].sts
& TPM_TIS_STS_DATA_AVAILABLE
)) {
340 len
= tpm_tis_get_size_from_buffer(&tis
->loc
[locty
].r_buffer
);
342 ret
= tis
->loc
[locty
].r_buffer
.buffer
[tis
->loc
[locty
].r_offset
++];
343 if (tis
->loc
[locty
].r_offset
>= len
) {
345 tis
->loc
[locty
].sts
= TPM_TIS_STS_VALID
;
347 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_STS_VALID
);
350 DPRINTF("tpm_tis: tpm_tis_data_read byte 0x%02x [%d]\n",
351 ret
, tis
->loc
[locty
].r_offset
-1);
358 static void tpm_tis_dump_state(void *opaque
, hwaddr addr
)
360 static const unsigned regs
[] = {
362 TPM_TIS_REG_INT_ENABLE
,
363 TPM_TIS_REG_INT_VECTOR
,
364 TPM_TIS_REG_INT_STATUS
,
365 TPM_TIS_REG_INTF_CAPABILITY
,
371 uint8_t locty
= tpm_tis_locality_from_addr(addr
);
372 hwaddr base
= addr
& ~0xfff;
373 TPMState
*s
= opaque
;
374 TPMTISEmuState
*tis
= &s
->s
.tis
;
376 DPRINTF("tpm_tis: active locality : %d\n"
377 "tpm_tis: state of locality %d : %d\n"
378 "tpm_tis: register dump:\n",
380 locty
, tis
->loc
[locty
].state
);
382 for (idx
= 0; regs
[idx
] != 0xfff; idx
++) {
383 DPRINTF("tpm_tis: 0x%04x : 0x%08x\n", regs
[idx
],
384 (uint32_t)tpm_tis_mmio_read(opaque
, base
+ regs
[idx
], 4));
387 DPRINTF("tpm_tis: read offset : %d\n"
388 "tpm_tis: result buffer : ",
389 tis
->loc
[locty
].r_offset
);
391 idx
< tpm_tis_get_size_from_buffer(&tis
->loc
[locty
].r_buffer
);
394 tis
->loc
[locty
].r_offset
== idx
? '>' : ' ',
395 tis
->loc
[locty
].r_buffer
.buffer
[idx
],
396 ((idx
& 0xf) == 0xf) ? "\ntpm_tis: " : "");
399 "tpm_tis: write offset : %d\n"
400 "tpm_tis: request buffer: ",
401 tis
->loc
[locty
].w_offset
);
403 idx
< tpm_tis_get_size_from_buffer(&tis
->loc
[locty
].w_buffer
);
406 tis
->loc
[locty
].w_offset
== idx
? '>' : ' ',
407 tis
->loc
[locty
].w_buffer
.buffer
[idx
],
408 ((idx
& 0xf) == 0xf) ? "\ntpm_tis: " : "");
415 * Read a register of the TIS interface
416 * See specs pages 33-63 for description of the registers
418 static uint64_t tpm_tis_mmio_read(void *opaque
, hwaddr addr
,
421 TPMState
*s
= opaque
;
422 TPMTISEmuState
*tis
= &s
->s
.tis
;
423 uint16_t offset
= addr
& 0xffc;
424 uint8_t shift
= (addr
& 0x3) * 8;
425 uint32_t val
= 0xffffffff;
426 uint8_t locty
= tpm_tis_locality_from_addr(addr
);
429 if (s
->be_driver
->ops
->had_startup_error(s
->be_driver
)) {
434 case TPM_TIS_REG_ACCESS
:
435 /* never show the SEIZE flag even though we use it internally */
436 val
= tis
->loc
[locty
].access
& ~TPM_TIS_ACCESS_SEIZE
;
437 /* the pending flag is always calculated */
438 if (tpm_tis_check_request_use_except(s
, locty
)) {
439 val
|= TPM_TIS_ACCESS_PENDING_REQUEST
;
441 val
|= !s
->be_driver
->ops
->get_tpm_established_flag(s
->be_driver
);
443 case TPM_TIS_REG_INT_ENABLE
:
444 val
= tis
->loc
[locty
].inte
;
446 case TPM_TIS_REG_INT_VECTOR
:
449 case TPM_TIS_REG_INT_STATUS
:
450 val
= tis
->loc
[locty
].ints
;
452 case TPM_TIS_REG_INTF_CAPABILITY
:
453 val
= TPM_TIS_CAPABILITIES_SUPPORTED
;
455 case TPM_TIS_REG_STS
:
456 if (tis
->active_locty
== locty
) {
457 if ((tis
->loc
[locty
].sts
& TPM_TIS_STS_DATA_AVAILABLE
)) {
458 val
= TPM_TIS_BURST_COUNT(
459 tpm_tis_get_size_from_buffer(&tis
->loc
[locty
].r_buffer
)
460 - tis
->loc
[locty
].r_offset
) | tis
->loc
[locty
].sts
;
462 avail
= tis
->loc
[locty
].w_buffer
.size
463 - tis
->loc
[locty
].w_offset
;
465 * byte-sized reads should not return 0x00 for 0x100
468 if (size
== 1 && avail
> 0xff) {
471 val
= TPM_TIS_BURST_COUNT(avail
) | tis
->loc
[locty
].sts
;
475 case TPM_TIS_REG_DATA_FIFO
:
476 if (tis
->active_locty
== locty
) {
477 switch (tis
->loc
[locty
].state
) {
478 case TPM_TIS_STATE_COMPLETION
:
479 val
= tpm_tis_data_read(s
, locty
);
482 val
= TPM_TIS_NO_DATA_BYTE
;
487 case TPM_TIS_REG_DID_VID
:
488 val
= (TPM_TIS_TPM_DID
<< 16) | TPM_TIS_TPM_VID
;
490 case TPM_TIS_REG_RID
:
491 val
= TPM_TIS_TPM_RID
;
494 case TPM_TIS_REG_DEBUG
:
495 tpm_tis_dump_state(opaque
, addr
);
504 DPRINTF("tpm_tis: read.%u(%08x) = %08x\n", size
, (int)addr
, (uint32_t)val
);
510 * Write a value to a register of the TIS interface
511 * See specs pages 33-63 for description of the registers
513 static void tpm_tis_mmio_write_intern(void *opaque
, hwaddr addr
,
514 uint64_t val
, unsigned size
,
517 TPMState
*s
= opaque
;
518 TPMTISEmuState
*tis
= &s
->s
.tis
;
519 uint16_t off
= addr
& 0xfff;
520 uint8_t locty
= tpm_tis_locality_from_addr(addr
);
521 uint8_t active_locty
, l
;
522 int c
, set_new_locty
= 1;
525 DPRINTF("tpm_tis: write.%u(%08x) = %08x\n", size
, (int)addr
, (uint32_t)val
);
527 if (locty
== 4 && !hw_access
) {
528 DPRINTF("tpm_tis: Access to locality 4 only allowed from hardware\n");
532 if (s
->be_driver
->ops
->had_startup_error(s
->be_driver
)) {
537 case TPM_TIS_REG_ACCESS
:
539 if ((val
& TPM_TIS_ACCESS_SEIZE
)) {
540 val
&= ~(TPM_TIS_ACCESS_REQUEST_USE
|
541 TPM_TIS_ACCESS_ACTIVE_LOCALITY
);
544 active_locty
= tis
->active_locty
;
546 if ((val
& TPM_TIS_ACCESS_ACTIVE_LOCALITY
)) {
547 /* give up locality if currently owned */
548 if (tis
->active_locty
== locty
) {
549 DPRINTF("tpm_tis: Releasing locality %d\n", locty
);
551 uint8_t newlocty
= TPM_TIS_NO_LOCALITY
;
552 /* anybody wants the locality ? */
553 for (c
= TPM_TIS_NUM_LOCALITIES
- 1; c
>= 0; c
--) {
554 if ((tis
->loc
[c
].access
& TPM_TIS_ACCESS_REQUEST_USE
)) {
555 DPRINTF("tpm_tis: Locality %d requests use.\n", c
);
560 DPRINTF("tpm_tis: TPM_TIS_ACCESS_ACTIVE_LOCALITY: "
561 "Next active locality: %d\n",
564 if (TPM_TIS_IS_VALID_LOCTY(newlocty
)) {
566 tpm_tis_prep_abort(s
, locty
, newlocty
);
568 active_locty
= TPM_TIS_NO_LOCALITY
;
571 /* not currently the owner; clear a pending request */
572 tis
->loc
[locty
].access
&= ~TPM_TIS_ACCESS_REQUEST_USE
;
576 if ((val
& TPM_TIS_ACCESS_BEEN_SEIZED
)) {
577 tis
->loc
[locty
].access
&= ~TPM_TIS_ACCESS_BEEN_SEIZED
;
580 if ((val
& TPM_TIS_ACCESS_SEIZE
)) {
582 * allow seize if a locality is active and the requesting
583 * locality is higher than the one that's active
585 * allow seize for requesting locality if no locality is
588 while ((TPM_TIS_IS_VALID_LOCTY(tis
->active_locty
) &&
589 locty
> tis
->active_locty
) ||
590 !TPM_TIS_IS_VALID_LOCTY(tis
->active_locty
)) {
591 bool higher_seize
= FALSE
;
593 /* already a pending SEIZE ? */
594 if ((tis
->loc
[locty
].access
& TPM_TIS_ACCESS_SEIZE
)) {
598 /* check for ongoing seize by a higher locality */
599 for (l
= locty
+ 1; l
< TPM_TIS_NUM_LOCALITIES
; l
++) {
600 if ((tis
->loc
[l
].access
& TPM_TIS_ACCESS_SEIZE
)) {
610 /* cancel any seize by a lower locality */
611 for (l
= 0; l
< locty
- 1; l
++) {
612 tis
->loc
[l
].access
&= ~TPM_TIS_ACCESS_SEIZE
;
615 tis
->loc
[locty
].access
|= TPM_TIS_ACCESS_SEIZE
;
616 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: "
617 "Locality %d seized from locality %d\n",
618 locty
, tis
->active_locty
);
619 DPRINTF("tpm_tis: TPM_TIS_ACCESS_SEIZE: Initiating abort.\n");
621 tpm_tis_prep_abort(s
, tis
->active_locty
, locty
);
626 if ((val
& TPM_TIS_ACCESS_REQUEST_USE
)) {
627 if (tis
->active_locty
!= locty
) {
628 if (TPM_TIS_IS_VALID_LOCTY(tis
->active_locty
)) {
629 tis
->loc
[locty
].access
|= TPM_TIS_ACCESS_REQUEST_USE
;
631 /* no locality active -> make this one active now */
632 active_locty
= locty
;
638 tpm_tis_new_active_locality(s
, active_locty
);
642 case TPM_TIS_REG_INT_ENABLE
:
643 if (tis
->active_locty
!= locty
) {
647 tis
->loc
[locty
].inte
= (val
& (TPM_TIS_INT_ENABLED
|
648 TPM_TIS_INT_POLARITY_MASK
|
649 TPM_TIS_INTERRUPTS_SUPPORTED
));
651 case TPM_TIS_REG_INT_VECTOR
:
652 /* hard wired -- ignore */
654 case TPM_TIS_REG_INT_STATUS
:
655 if (tis
->active_locty
!= locty
) {
659 /* clearing of interrupt flags */
660 if (((val
& TPM_TIS_INTERRUPTS_SUPPORTED
)) &&
661 (tis
->loc
[locty
].ints
& TPM_TIS_INTERRUPTS_SUPPORTED
)) {
662 tis
->loc
[locty
].ints
&= ~val
;
663 if (tis
->loc
[locty
].ints
== 0) {
664 qemu_irq_lower(tis
->irq
);
665 DPRINTF("tpm_tis: Lowering IRQ\n");
668 tis
->loc
[locty
].ints
&= ~(val
& TPM_TIS_INTERRUPTS_SUPPORTED
);
670 case TPM_TIS_REG_STS
:
671 if (tis
->active_locty
!= locty
) {
675 val
&= (TPM_TIS_STS_COMMAND_READY
| TPM_TIS_STS_TPM_GO
|
676 TPM_TIS_STS_RESPONSE_RETRY
);
678 if (val
== TPM_TIS_STS_COMMAND_READY
) {
679 switch (tis
->loc
[locty
].state
) {
681 case TPM_TIS_STATE_READY
:
682 tis
->loc
[locty
].w_offset
= 0;
683 tis
->loc
[locty
].r_offset
= 0;
686 case TPM_TIS_STATE_IDLE
:
687 tis
->loc
[locty
].sts
= TPM_TIS_STS_COMMAND_READY
;
688 tis
->loc
[locty
].state
= TPM_TIS_STATE_READY
;
689 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_COMMAND_READY
);
692 case TPM_TIS_STATE_EXECUTION
:
693 case TPM_TIS_STATE_RECEPTION
:
694 /* abort currently running command */
695 DPRINTF("tpm_tis: %s: Initiating abort.\n",
697 tpm_tis_prep_abort(s
, locty
, locty
);
700 case TPM_TIS_STATE_COMPLETION
:
701 tis
->loc
[locty
].w_offset
= 0;
702 tis
->loc
[locty
].r_offset
= 0;
703 /* shortcut to ready state with C/R set */
704 tis
->loc
[locty
].state
= TPM_TIS_STATE_READY
;
705 if (!(tis
->loc
[locty
].sts
& TPM_TIS_STS_COMMAND_READY
)) {
706 tis
->loc
[locty
].sts
= TPM_TIS_STS_COMMAND_READY
;
707 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_COMMAND_READY
);
709 tis
->loc
[locty
].sts
&= ~(TPM_TIS_STS_DATA_AVAILABLE
);
713 } else if (val
== TPM_TIS_STS_TPM_GO
) {
714 switch (tis
->loc
[locty
].state
) {
715 case TPM_TIS_STATE_RECEPTION
:
716 if ((tis
->loc
[locty
].sts
& TPM_TIS_STS_EXPECT
) == 0) {
717 tpm_tis_tpm_send(s
, locty
);
724 } else if (val
== TPM_TIS_STS_RESPONSE_RETRY
) {
725 switch (tis
->loc
[locty
].state
) {
726 case TPM_TIS_STATE_COMPLETION
:
727 tis
->loc
[locty
].r_offset
= 0;
728 tis
->loc
[locty
].sts
= TPM_TIS_STS_VALID
|
729 TPM_TIS_STS_DATA_AVAILABLE
;
737 case TPM_TIS_REG_DATA_FIFO
:
739 if (tis
->active_locty
!= locty
) {
743 if (tis
->loc
[locty
].state
== TPM_TIS_STATE_IDLE
||
744 tis
->loc
[locty
].state
== TPM_TIS_STATE_EXECUTION
||
745 tis
->loc
[locty
].state
== TPM_TIS_STATE_COMPLETION
) {
748 DPRINTF("tpm_tis: Byte to send to TPM: %02x\n", (uint8_t)val
);
749 if (tis
->loc
[locty
].state
== TPM_TIS_STATE_READY
) {
750 tis
->loc
[locty
].state
= TPM_TIS_STATE_RECEPTION
;
751 tis
->loc
[locty
].sts
= TPM_TIS_STS_EXPECT
| TPM_TIS_STS_VALID
;
754 if ((tis
->loc
[locty
].sts
& TPM_TIS_STS_EXPECT
)) {
755 if (tis
->loc
[locty
].w_offset
< tis
->loc
[locty
].w_buffer
.size
) {
756 tis
->loc
[locty
].w_buffer
.
757 buffer
[tis
->loc
[locty
].w_offset
++] = (uint8_t)val
;
759 tis
->loc
[locty
].sts
= TPM_TIS_STS_VALID
;
763 /* check for complete packet */
764 if (tis
->loc
[locty
].w_offset
> 5 &&
765 (tis
->loc
[locty
].sts
& TPM_TIS_STS_EXPECT
)) {
766 /* we have a packet length - see if we have all of it */
768 bool needIrq
= !(tis
->loc
[locty
].sts
& TPM_TIS_STS_VALID
);
770 len
= tpm_tis_get_size_from_buffer(&tis
->loc
[locty
].w_buffer
);
771 if (len
> tis
->loc
[locty
].w_offset
) {
772 tis
->loc
[locty
].sts
= TPM_TIS_STS_EXPECT
|
775 /* packet complete */
776 tis
->loc
[locty
].sts
= TPM_TIS_STS_VALID
;
780 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_STS_VALID
);
789 static void tpm_tis_mmio_write(void *opaque
, hwaddr addr
,
790 uint64_t val
, unsigned size
)
792 return tpm_tis_mmio_write_intern(opaque
, addr
, val
, size
, false);
795 static const MemoryRegionOps tpm_tis_memory_ops
= {
796 .read
= tpm_tis_mmio_read
,
797 .write
= tpm_tis_mmio_write
,
798 .endianness
= DEVICE_LITTLE_ENDIAN
,
800 .min_access_size
= 1,
801 .max_access_size
= 4,
805 static int tpm_tis_do_startup_tpm(TPMState
*s
)
807 return s
->be_driver
->ops
->startup_tpm(s
->be_driver
);
811 * This function is called when the machine starts, resets or due to
814 static void tpm_tis_reset(DeviceState
*dev
)
816 TPMState
*s
= TPM(dev
);
817 TPMTISEmuState
*tis
= &s
->s
.tis
;
820 s
->be_driver
->ops
->reset(s
->be_driver
);
822 tis
->active_locty
= TPM_TIS_NO_LOCALITY
;
823 tis
->next_locty
= TPM_TIS_NO_LOCALITY
;
824 tis
->aborting_locty
= TPM_TIS_NO_LOCALITY
;
826 for (c
= 0; c
< TPM_TIS_NUM_LOCALITIES
; c
++) {
827 tis
->loc
[c
].access
= TPM_TIS_ACCESS_TPM_REG_VALID_STS
;
829 tis
->loc
[c
].inte
= TPM_TIS_INT_POLARITY_LOW_LEVEL
;
830 tis
->loc
[c
].ints
= 0;
831 tis
->loc
[c
].state
= TPM_TIS_STATE_IDLE
;
833 tis
->loc
[c
].w_offset
= 0;
834 s
->be_driver
->ops
->realloc_buffer(&tis
->loc
[c
].w_buffer
);
835 tis
->loc
[c
].r_offset
= 0;
836 s
->be_driver
->ops
->realloc_buffer(&tis
->loc
[c
].r_buffer
);
839 tpm_tis_do_startup_tpm(s
);
842 static const VMStateDescription vmstate_tpm_tis
= {
847 static Property tpm_tis_properties
[] = {
848 DEFINE_PROP_UINT32("irq", TPMState
,
849 s
.tis
.irq_num
, TPM_TIS_IRQ
),
850 DEFINE_PROP_STRING("tpmdev", TPMState
, backend
),
851 DEFINE_PROP_END_OF_LIST(),
854 static void tpm_tis_realizefn(DeviceState
*dev
, Error
**errp
)
856 TPMState
*s
= TPM(dev
);
857 TPMTISEmuState
*tis
= &s
->s
.tis
;
859 s
->be_driver
= qemu_find_tpm(s
->backend
);
861 error_setg(errp
, "tpm_tis: backend driver with id %s could not be "
862 "found", s
->backend
);
866 s
->be_driver
->fe_model
= TPM_MODEL_TPM_TIS
;
868 if (s
->be_driver
->ops
->init(s
->be_driver
, s
, tpm_tis_receive_cb
)) {
869 error_setg(errp
, "tpm_tis: backend driver with id %s could not be "
870 "initialized", s
->backend
);
874 if (tis
->irq_num
> 15) {
875 error_setg(errp
, "tpm_tis: IRQ %d for TPM TIS is outside valid range "
876 "of 0 to 15.\n", tis
->irq_num
);
880 tis
->bh
= qemu_bh_new(tpm_tis_receive_bh
, s
);
882 isa_init_irq(&s
->busdev
, &tis
->irq
, tis
->irq_num
);
885 static void tpm_tis_initfn(Object
*obj
)
887 ISADevice
*dev
= ISA_DEVICE(obj
);
888 TPMState
*s
= TPM(obj
);
890 memory_region_init_io(&s
->mmio
, &tpm_tis_memory_ops
, s
, "tpm-tis-mmio",
891 TPM_TIS_NUM_LOCALITIES
<< TPM_TIS_LOCALITY_SHIFT
);
892 memory_region_add_subregion(isa_address_space(dev
), TPM_TIS_ADDR_BASE
,
896 static void tpm_tis_uninitfn(Object
*obj
)
898 TPMState
*s
= TPM(obj
);
900 memory_region_del_subregion(get_system_memory(), &s
->mmio
);
901 memory_region_destroy(&s
->mmio
);
904 static void tpm_tis_class_init(ObjectClass
*klass
, void *data
)
906 DeviceClass
*dc
= DEVICE_CLASS(klass
);
908 dc
->realize
= tpm_tis_realizefn
;
909 dc
->props
= tpm_tis_properties
;
910 dc
->reset
= tpm_tis_reset
;
911 dc
->vmsd
= &vmstate_tpm_tis
;
914 static const TypeInfo tpm_tis_info
= {
915 .name
= TYPE_TPM_TIS
,
916 .parent
= TYPE_ISA_DEVICE
,
917 .instance_size
= sizeof(TPMState
),
918 .instance_init
= tpm_tis_initfn
,
919 .instance_finalize
= tpm_tis_uninitfn
,
920 .class_init
= tpm_tis_class_init
,
923 static void tpm_tis_register(void)
925 type_register_static(&tpm_tis_info
);
926 tpm_register_model(TPM_MODEL_TPM_TIS
);
929 type_init(tpm_tis_register
)