2 * tpm_tis_common.c - QEMU's TPM TIS interface emulator
3 * device agnostic functions
5 * Copyright (C) 2006,2010-2013 IBM Corporation
8 * Stefan Berger <stefanb@us.ibm.com>
9 * David Safford <safford@us.ibm.com>
11 * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at>
13 * This work is licensed under the terms of the GNU GPL, version 2 or later.
14 * See the COPYING file in the top-level directory.
16 * Implementation of the TIS interface according to specs found at
17 * http://www.trustedcomputinggroup.org. This implementation currently
18 * supports version 1.3, 21 March 2013
19 * In the developers menu choose the PC Client section then find the TIS
22 * TPM TIS for TPM 2 implementation following TCG PC Client Platform
23 * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
25 #include "qemu/osdep.h"
27 #include "hw/isa/isa.h"
28 #include "qapi/error.h"
29 #include "qemu/bswap.h"
30 #include "qemu/crc-ccitt.h"
31 #include "qemu/module.h"
33 #include "hw/acpi/tpm.h"
34 #include "hw/pci/pci_ids.h"
35 #include "hw/qdev-properties.h"
36 #include "migration/vmstate.h"
37 #include "sysemu/tpm_backend.h"
38 #include "sysemu/tpm_util.h"
46 /* local prototypes */
48 static uint64_t tpm_tis_mmio_read(void *opaque
, hwaddr addr
,
51 /* utility functions */
53 static uint8_t tpm_tis_locality_from_addr(hwaddr addr
)
57 locty
= (uint8_t)((addr
>> TPM_TIS_LOCALITY_SHIFT
) & 0x7);
58 assert(TPM_TIS_IS_VALID_LOCTY(locty
));
65 * Set the given flags in the STS register by clearing the register but
66 * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting
69 * The SELFTEST_DONE flag is acquired from the backend that determines it by
70 * peeking into TPM commands.
72 * A VM suspend/resume will preserve the flag by storing it into the VM
73 * device state, but the backend will not remember it when QEMU is started
74 * again. Therefore, we cache the flag here. Once set, it will not be unset
77 static void tpm_tis_sts_set(TPMLocality
*l
, uint32_t flags
)
79 l
->sts
&= TPM_TIS_STS_SELFTEST_DONE
| TPM_TIS_STS_TPM_FAMILY_MASK
;
84 * Send a request to the TPM.
86 static void tpm_tis_tpm_send(TPMState
*s
, uint8_t locty
)
88 tpm_util_show_buffer(s
->buffer
, s
->be_buffer_size
, "To TPM");
91 * rw_offset serves as length indicator for length of data;
92 * it's reset when the response comes back
94 s
->loc
[locty
].state
= TPM_TIS_STATE_EXECUTION
;
96 s
->cmd
= (TPMBackendCmd
) {
99 .in_len
= s
->rw_offset
,
101 .out_len
= s
->be_buffer_size
,
104 tpm_backend_deliver_request(s
->be_driver
, &s
->cmd
);
107 /* raise an interrupt if allowed */
108 static void tpm_tis_raise_irq(TPMState
*s
, uint8_t locty
, uint32_t irqmask
)
110 if (!TPM_TIS_IS_VALID_LOCTY(locty
)) {
114 if ((s
->loc
[locty
].inte
& TPM_TIS_INT_ENABLED
) &&
115 (s
->loc
[locty
].inte
& irqmask
)) {
116 trace_tpm_tis_raise_irq(irqmask
);
117 qemu_irq_raise(s
->irq
);
118 s
->loc
[locty
].ints
|= irqmask
;
122 static uint32_t tpm_tis_check_request_use_except(TPMState
*s
, uint8_t locty
)
126 for (l
= 0; l
< TPM_TIS_NUM_LOCALITIES
; l
++) {
130 if ((s
->loc
[l
].access
& TPM_TIS_ACCESS_REQUEST_USE
)) {
138 static void tpm_tis_new_active_locality(TPMState
*s
, uint8_t new_active_locty
)
140 bool change
= (s
->active_locty
!= new_active_locty
);
144 if (change
&& TPM_TIS_IS_VALID_LOCTY(s
->active_locty
)) {
145 is_seize
= TPM_TIS_IS_VALID_LOCTY(new_active_locty
) &&
146 s
->loc
[new_active_locty
].access
& TPM_TIS_ACCESS_SEIZE
;
149 mask
= ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY
);
151 mask
= ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY
|
152 TPM_TIS_ACCESS_REQUEST_USE
);
154 /* reset flags on the old active locality */
155 s
->loc
[s
->active_locty
].access
&= mask
;
158 s
->loc
[s
->active_locty
].access
|= TPM_TIS_ACCESS_BEEN_SEIZED
;
162 s
->active_locty
= new_active_locty
;
164 trace_tpm_tis_new_active_locality(s
->active_locty
);
166 if (TPM_TIS_IS_VALID_LOCTY(new_active_locty
)) {
167 /* set flags on the new active locality */
168 s
->loc
[new_active_locty
].access
|= TPM_TIS_ACCESS_ACTIVE_LOCALITY
;
169 s
->loc
[new_active_locty
].access
&= ~(TPM_TIS_ACCESS_REQUEST_USE
|
170 TPM_TIS_ACCESS_SEIZE
);
174 tpm_tis_raise_irq(s
, s
->active_locty
, TPM_TIS_INT_LOCALITY_CHANGED
);
178 /* abort -- this function switches the locality */
179 static void tpm_tis_abort(TPMState
*s
)
183 trace_tpm_tis_abort(s
->next_locty
);
186 * Need to react differently depending on who's aborting now and
187 * which locality will become active afterwards.
189 if (s
->aborting_locty
== s
->next_locty
) {
190 s
->loc
[s
->aborting_locty
].state
= TPM_TIS_STATE_READY
;
191 tpm_tis_sts_set(&s
->loc
[s
->aborting_locty
],
192 TPM_TIS_STS_COMMAND_READY
);
193 tpm_tis_raise_irq(s
, s
->aborting_locty
, TPM_TIS_INT_COMMAND_READY
);
196 /* locality after abort is another one than the current one */
197 tpm_tis_new_active_locality(s
, s
->next_locty
);
199 s
->next_locty
= TPM_TIS_NO_LOCALITY
;
200 /* nobody's aborting a command anymore */
201 s
->aborting_locty
= TPM_TIS_NO_LOCALITY
;
204 /* prepare aborting current command */
205 static void tpm_tis_prep_abort(TPMState
*s
, uint8_t locty
, uint8_t newlocty
)
209 assert(TPM_TIS_IS_VALID_LOCTY(newlocty
));
211 s
->aborting_locty
= locty
; /* may also be TPM_TIS_NO_LOCALITY */
212 s
->next_locty
= newlocty
; /* locality after successful abort */
215 * only abort a command using an interrupt if currently executing
216 * a command AND if there's a valid connection to the vTPM.
218 for (busy_locty
= 0; busy_locty
< TPM_TIS_NUM_LOCALITIES
; busy_locty
++) {
219 if (s
->loc
[busy_locty
].state
== TPM_TIS_STATE_EXECUTION
) {
221 * request the backend to cancel. Some backends may not
224 tpm_backend_cancel_cmd(s
->be_driver
);
233 * Callback from the TPM to indicate that the response was received.
235 void tpm_tis_request_completed(TPMState
*s
, int ret
)
237 uint8_t locty
= s
->cmd
.locty
;
240 assert(TPM_TIS_IS_VALID_LOCTY(locty
));
242 if (s
->cmd
.selftest_done
) {
243 for (l
= 0; l
< TPM_TIS_NUM_LOCALITIES
; l
++) {
244 s
->loc
[l
].sts
|= TPM_TIS_STS_SELFTEST_DONE
;
248 /* FIXME: report error if ret != 0 */
249 tpm_tis_sts_set(&s
->loc
[locty
],
250 TPM_TIS_STS_VALID
| TPM_TIS_STS_DATA_AVAILABLE
);
251 s
->loc
[locty
].state
= TPM_TIS_STATE_COMPLETION
;
254 tpm_util_show_buffer(s
->buffer
, s
->be_buffer_size
, "From TPM");
256 if (TPM_TIS_IS_VALID_LOCTY(s
->next_locty
)) {
260 tpm_tis_raise_irq(s
, locty
,
261 TPM_TIS_INT_DATA_AVAILABLE
| TPM_TIS_INT_STS_VALID
);
265 * Read a byte of response data
267 static uint32_t tpm_tis_data_read(TPMState
*s
, uint8_t locty
)
269 uint32_t ret
= TPM_TIS_NO_DATA_BYTE
;
272 if ((s
->loc
[locty
].sts
& TPM_TIS_STS_DATA_AVAILABLE
)) {
273 len
= MIN(tpm_cmd_get_size(&s
->buffer
),
276 ret
= s
->buffer
[s
->rw_offset
++];
277 if (s
->rw_offset
>= len
) {
279 tpm_tis_sts_set(&s
->loc
[locty
], TPM_TIS_STS_VALID
);
280 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_STS_VALID
);
282 trace_tpm_tis_data_read(ret
, s
->rw_offset
- 1);
289 static void tpm_tis_dump_state(TPMState
*s
, hwaddr addr
)
291 static const unsigned regs
[] = {
293 TPM_TIS_REG_INT_ENABLE
,
294 TPM_TIS_REG_INT_VECTOR
,
295 TPM_TIS_REG_INT_STATUS
,
296 TPM_TIS_REG_INTF_CAPABILITY
,
302 uint8_t locty
= tpm_tis_locality_from_addr(addr
);
303 hwaddr base
= addr
& ~0xfff;
305 printf("tpm_tis: active locality : %d\n"
306 "tpm_tis: state of locality %d : %d\n"
307 "tpm_tis: register dump:\n",
309 locty
, s
->loc
[locty
].state
);
311 for (idx
= 0; regs
[idx
] != 0xfff; idx
++) {
312 printf("tpm_tis: 0x%04x : 0x%08x\n", regs
[idx
],
313 (int)tpm_tis_mmio_read(s
, base
+ regs
[idx
], 4));
316 printf("tpm_tis: r/w offset : %d\n"
317 "tpm_tis: result buffer : ",
320 idx
< MIN(tpm_cmd_get_size(&s
->buffer
), s
->be_buffer_size
);
323 s
->rw_offset
== idx
? '>' : ' ',
325 ((idx
& 0xf) == 0xf) ? "\ntpm_tis: " : "");
332 * Read a register of the TIS interface
333 * See specs pages 33-63 for description of the registers
335 static uint64_t tpm_tis_mmio_read(void *opaque
, hwaddr addr
,
338 TPMState
*s
= opaque
;
339 uint16_t offset
= addr
& 0xffc;
340 uint8_t shift
= (addr
& 0x3) * 8;
341 uint32_t val
= 0xffffffff;
342 uint8_t locty
= tpm_tis_locality_from_addr(addr
);
346 if (tpm_backend_had_startup_error(s
->be_driver
)) {
351 case TPM_TIS_REG_ACCESS
:
352 /* never show the SEIZE flag even though we use it internally */
353 val
= s
->loc
[locty
].access
& ~TPM_TIS_ACCESS_SEIZE
;
354 /* the pending flag is always calculated */
355 if (tpm_tis_check_request_use_except(s
, locty
)) {
356 val
|= TPM_TIS_ACCESS_PENDING_REQUEST
;
358 val
|= !tpm_backend_get_tpm_established_flag(s
->be_driver
);
360 case TPM_TIS_REG_INT_ENABLE
:
361 val
= s
->loc
[locty
].inte
;
363 case TPM_TIS_REG_INT_VECTOR
:
366 case TPM_TIS_REG_INT_STATUS
:
367 val
= s
->loc
[locty
].ints
;
369 case TPM_TIS_REG_INTF_CAPABILITY
:
370 switch (s
->be_tpm_version
) {
371 case TPM_VERSION_UNSPEC
:
374 case TPM_VERSION_1_2
:
375 val
= TPM_TIS_CAPABILITIES_SUPPORTED1_3
;
377 case TPM_VERSION_2_0
:
378 val
= TPM_TIS_CAPABILITIES_SUPPORTED2_0
;
382 case TPM_TIS_REG_STS
:
383 if (s
->active_locty
== locty
) {
384 if ((s
->loc
[locty
].sts
& TPM_TIS_STS_DATA_AVAILABLE
)) {
385 val
= TPM_TIS_BURST_COUNT(
386 MIN(tpm_cmd_get_size(&s
->buffer
),
388 - s
->rw_offset
) | s
->loc
[locty
].sts
;
390 avail
= s
->be_buffer_size
- s
->rw_offset
;
392 * byte-sized reads should not return 0x00 for 0x100
395 if (size
== 1 && avail
> 0xff) {
398 val
= TPM_TIS_BURST_COUNT(avail
) | s
->loc
[locty
].sts
;
402 case TPM_TIS_REG_DATA_FIFO
:
403 case TPM_TIS_REG_DATA_XFIFO
... TPM_TIS_REG_DATA_XFIFO_END
:
404 if (s
->active_locty
== locty
) {
405 if (size
> 4 - (addr
& 0x3)) {
406 /* prevent access beyond FIFO */
407 size
= 4 - (addr
& 0x3);
412 switch (s
->loc
[locty
].state
) {
413 case TPM_TIS_STATE_COMPLETION
:
414 v
= tpm_tis_data_read(s
, locty
);
417 v
= TPM_TIS_NO_DATA_BYTE
;
424 shift
= 0; /* no more adjustments */
427 case TPM_TIS_REG_INTERFACE_ID
:
428 val
= s
->loc
[locty
].iface_id
;
430 case TPM_TIS_REG_DID_VID
:
431 val
= (TPM_TIS_TPM_DID
<< 16) | TPM_TIS_TPM_VID
;
433 case TPM_TIS_REG_RID
:
434 val
= TPM_TIS_TPM_RID
;
437 case TPM_TIS_REG_DEBUG
:
438 tpm_tis_dump_state(s
, addr
);
447 trace_tpm_tis_mmio_read(size
, addr
, val
);
453 * A wrapper read function so that it can be directly called without
456 uint32_t tpm_tis_read_data(TPMState
*s
, hwaddr addr
, unsigned size
)
458 return tpm_tis_mmio_read(s
, addr
, size
);
462 * Calculate current data buffer checksum
464 uint16_t tpm_tis_get_checksum(TPMState
*s
)
466 return bswap16(crc_ccitt(0, s
->buffer
, s
->rw_offset
));
470 * Write a value to a register of the TIS interface
471 * See specs pages 33-63 for description of the registers
473 static void tpm_tis_mmio_write(void *opaque
, hwaddr addr
,
474 uint64_t val
, unsigned size
)
476 TPMState
*s
= opaque
;
477 uint16_t off
= addr
& 0xffc;
478 uint8_t shift
= (addr
& 0x3) * 8;
479 uint8_t locty
= tpm_tis_locality_from_addr(addr
);
480 uint8_t active_locty
, l
;
481 int c
, set_new_locty
= 1;
483 uint32_t mask
= (size
== 1) ? 0xff : ((size
== 2) ? 0xffff : ~0);
485 trace_tpm_tis_mmio_write(size
, addr
, val
);
488 trace_tpm_tis_mmio_write_locty4();
492 if (tpm_backend_had_startup_error(s
->be_driver
)) {
506 case TPM_TIS_REG_ACCESS
:
508 if ((val
& TPM_TIS_ACCESS_SEIZE
)) {
509 val
&= ~(TPM_TIS_ACCESS_REQUEST_USE
|
510 TPM_TIS_ACCESS_ACTIVE_LOCALITY
);
513 active_locty
= s
->active_locty
;
515 if ((val
& TPM_TIS_ACCESS_ACTIVE_LOCALITY
)) {
516 /* give up locality if currently owned */
517 if (s
->active_locty
== locty
) {
518 trace_tpm_tis_mmio_write_release_locty(locty
);
520 uint8_t newlocty
= TPM_TIS_NO_LOCALITY
;
521 /* anybody wants the locality ? */
522 for (c
= TPM_TIS_NUM_LOCALITIES
- 1; c
>= 0; c
--) {
523 if ((s
->loc
[c
].access
& TPM_TIS_ACCESS_REQUEST_USE
)) {
524 trace_tpm_tis_mmio_write_locty_req_use(c
);
529 trace_tpm_tis_mmio_write_next_locty(newlocty
);
531 if (TPM_TIS_IS_VALID_LOCTY(newlocty
)) {
533 tpm_tis_prep_abort(s
, locty
, newlocty
);
535 active_locty
= TPM_TIS_NO_LOCALITY
;
538 /* not currently the owner; clear a pending request */
539 s
->loc
[locty
].access
&= ~TPM_TIS_ACCESS_REQUEST_USE
;
543 if ((val
& TPM_TIS_ACCESS_BEEN_SEIZED
)) {
544 s
->loc
[locty
].access
&= ~TPM_TIS_ACCESS_BEEN_SEIZED
;
547 if ((val
& TPM_TIS_ACCESS_SEIZE
)) {
549 * allow seize if a locality is active and the requesting
550 * locality is higher than the one that's active
552 * allow seize for requesting locality if no locality is
555 while ((TPM_TIS_IS_VALID_LOCTY(s
->active_locty
) &&
556 locty
> s
->active_locty
) ||
557 !TPM_TIS_IS_VALID_LOCTY(s
->active_locty
)) {
558 bool higher_seize
= false;
560 /* already a pending SEIZE ? */
561 if ((s
->loc
[locty
].access
& TPM_TIS_ACCESS_SEIZE
)) {
565 /* check for ongoing seize by a higher locality */
566 for (l
= locty
+ 1; l
< TPM_TIS_NUM_LOCALITIES
; l
++) {
567 if ((s
->loc
[l
].access
& TPM_TIS_ACCESS_SEIZE
)) {
577 /* cancel any seize by a lower locality */
578 for (l
= 0; l
< locty
; l
++) {
579 s
->loc
[l
].access
&= ~TPM_TIS_ACCESS_SEIZE
;
582 s
->loc
[locty
].access
|= TPM_TIS_ACCESS_SEIZE
;
584 trace_tpm_tis_mmio_write_locty_seized(locty
, s
->active_locty
);
585 trace_tpm_tis_mmio_write_init_abort();
588 tpm_tis_prep_abort(s
, s
->active_locty
, locty
);
593 if ((val
& TPM_TIS_ACCESS_REQUEST_USE
)) {
594 if (s
->active_locty
!= locty
) {
595 if (TPM_TIS_IS_VALID_LOCTY(s
->active_locty
)) {
596 s
->loc
[locty
].access
|= TPM_TIS_ACCESS_REQUEST_USE
;
598 /* no locality active -> make this one active now */
599 active_locty
= locty
;
605 tpm_tis_new_active_locality(s
, active_locty
);
609 case TPM_TIS_REG_INT_ENABLE
:
610 s
->loc
[locty
].inte
&= mask
;
611 s
->loc
[locty
].inte
|= (val
& (TPM_TIS_INT_ENABLED
|
612 TPM_TIS_INT_POLARITY_MASK
|
613 TPM_TIS_INTERRUPTS_SUPPORTED
));
615 case TPM_TIS_REG_INT_VECTOR
:
616 /* hard wired -- ignore */
618 case TPM_TIS_REG_INT_STATUS
:
619 /* clearing of interrupt flags */
620 if (((val
& TPM_TIS_INTERRUPTS_SUPPORTED
)) &&
621 (s
->loc
[locty
].ints
& TPM_TIS_INTERRUPTS_SUPPORTED
)) {
622 s
->loc
[locty
].ints
&= ~val
;
623 if (s
->loc
[locty
].ints
== 0) {
624 qemu_irq_lower(s
->irq
);
625 trace_tpm_tis_mmio_write_lowering_irq();
628 s
->loc
[locty
].ints
&= ~(val
& TPM_TIS_INTERRUPTS_SUPPORTED
);
630 case TPM_TIS_REG_STS
:
631 if (s
->active_locty
!= locty
) {
635 if (s
->be_tpm_version
== TPM_VERSION_2_0
) {
636 /* some flags that are only supported for TPM 2 */
637 if (val
& TPM_TIS_STS_COMMAND_CANCEL
) {
638 if (s
->loc
[locty
].state
== TPM_TIS_STATE_EXECUTION
) {
640 * request the backend to cancel. Some backends may not
643 tpm_backend_cancel_cmd(s
->be_driver
);
647 if (val
& TPM_TIS_STS_RESET_ESTABLISHMENT_BIT
) {
648 if (locty
== 3 || locty
== 4) {
649 tpm_backend_reset_tpm_established_flag(s
->be_driver
, locty
);
654 val
&= (TPM_TIS_STS_COMMAND_READY
| TPM_TIS_STS_TPM_GO
|
655 TPM_TIS_STS_RESPONSE_RETRY
);
657 if (val
== TPM_TIS_STS_COMMAND_READY
) {
658 switch (s
->loc
[locty
].state
) {
660 case TPM_TIS_STATE_READY
:
664 case TPM_TIS_STATE_IDLE
:
665 tpm_tis_sts_set(&s
->loc
[locty
], TPM_TIS_STS_COMMAND_READY
);
666 s
->loc
[locty
].state
= TPM_TIS_STATE_READY
;
667 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_COMMAND_READY
);
670 case TPM_TIS_STATE_EXECUTION
:
671 case TPM_TIS_STATE_RECEPTION
:
672 /* abort currently running command */
673 trace_tpm_tis_mmio_write_init_abort();
674 tpm_tis_prep_abort(s
, locty
, locty
);
677 case TPM_TIS_STATE_COMPLETION
:
679 /* shortcut to ready state with C/R set */
680 s
->loc
[locty
].state
= TPM_TIS_STATE_READY
;
681 if (!(s
->loc
[locty
].sts
& TPM_TIS_STS_COMMAND_READY
)) {
682 tpm_tis_sts_set(&s
->loc
[locty
],
683 TPM_TIS_STS_COMMAND_READY
);
684 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_COMMAND_READY
);
686 s
->loc
[locty
].sts
&= ~(TPM_TIS_STS_DATA_AVAILABLE
);
690 } else if (val
== TPM_TIS_STS_TPM_GO
) {
691 switch (s
->loc
[locty
].state
) {
692 case TPM_TIS_STATE_RECEPTION
:
693 if ((s
->loc
[locty
].sts
& TPM_TIS_STS_EXPECT
) == 0) {
694 tpm_tis_tpm_send(s
, locty
);
701 } else if (val
== TPM_TIS_STS_RESPONSE_RETRY
) {
702 switch (s
->loc
[locty
].state
) {
703 case TPM_TIS_STATE_COMPLETION
:
705 tpm_tis_sts_set(&s
->loc
[locty
],
707 TPM_TIS_STS_DATA_AVAILABLE
);
715 case TPM_TIS_REG_DATA_FIFO
:
716 case TPM_TIS_REG_DATA_XFIFO
... TPM_TIS_REG_DATA_XFIFO_END
:
718 if (s
->active_locty
!= locty
) {
722 if (s
->loc
[locty
].state
== TPM_TIS_STATE_IDLE
||
723 s
->loc
[locty
].state
== TPM_TIS_STATE_EXECUTION
||
724 s
->loc
[locty
].state
== TPM_TIS_STATE_COMPLETION
) {
727 trace_tpm_tis_mmio_write_data2send(val
, size
);
728 if (s
->loc
[locty
].state
== TPM_TIS_STATE_READY
) {
729 s
->loc
[locty
].state
= TPM_TIS_STATE_RECEPTION
;
730 tpm_tis_sts_set(&s
->loc
[locty
],
731 TPM_TIS_STS_EXPECT
| TPM_TIS_STS_VALID
);
735 if (size
> 4 - (addr
& 0x3)) {
736 /* prevent access beyond FIFO */
737 size
= 4 - (addr
& 0x3);
740 while ((s
->loc
[locty
].sts
& TPM_TIS_STS_EXPECT
) && size
> 0) {
741 if (s
->rw_offset
< s
->be_buffer_size
) {
742 s
->buffer
[s
->rw_offset
++] =
747 tpm_tis_sts_set(&s
->loc
[locty
], TPM_TIS_STS_VALID
);
751 /* check for complete packet */
752 if (s
->rw_offset
> 5 &&
753 (s
->loc
[locty
].sts
& TPM_TIS_STS_EXPECT
)) {
754 /* we have a packet length - see if we have all of it */
755 bool need_irq
= !(s
->loc
[locty
].sts
& TPM_TIS_STS_VALID
);
757 len
= tpm_cmd_get_size(&s
->buffer
);
758 if (len
> s
->rw_offset
) {
759 tpm_tis_sts_set(&s
->loc
[locty
],
760 TPM_TIS_STS_EXPECT
| TPM_TIS_STS_VALID
);
762 /* packet complete */
763 tpm_tis_sts_set(&s
->loc
[locty
], TPM_TIS_STS_VALID
);
766 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_STS_VALID
);
771 case TPM_TIS_REG_INTERFACE_ID
:
772 if (val
& TPM_TIS_IFACE_ID_INT_SEL_LOCK
) {
773 for (l
= 0; l
< TPM_TIS_NUM_LOCALITIES
; l
++) {
774 s
->loc
[l
].iface_id
|= TPM_TIS_IFACE_ID_INT_SEL_LOCK
;
782 * A wrapper write function so that it can be directly called without
785 void tpm_tis_write_data(TPMState
*s
, hwaddr addr
, uint64_t val
, uint32_t size
)
787 tpm_tis_mmio_write(s
, addr
, val
, size
);
790 const MemoryRegionOps tpm_tis_memory_ops
= {
791 .read
= tpm_tis_mmio_read
,
792 .write
= tpm_tis_mmio_write
,
793 .endianness
= DEVICE_LITTLE_ENDIAN
,
795 .min_access_size
= 1,
796 .max_access_size
= 4,
801 * Get the TPMVersion of the backend device being used
803 enum TPMVersion
tpm_tis_get_tpm_version(TPMState
*s
)
805 if (tpm_backend_had_startup_error(s
->be_driver
)) {
806 return TPM_VERSION_UNSPEC
;
809 return tpm_backend_get_tpm_version(s
->be_driver
);
813 * This function is called when the machine starts, resets or due to
816 void tpm_tis_reset(TPMState
*s
)
820 s
->be_tpm_version
= tpm_backend_get_tpm_version(s
->be_driver
);
821 s
->be_buffer_size
= MIN(tpm_backend_get_buffer_size(s
->be_driver
),
824 if (s
->ppi_enabled
) {
825 tpm_ppi_reset(&s
->ppi
);
827 tpm_backend_reset(s
->be_driver
);
829 s
->active_locty
= TPM_TIS_NO_LOCALITY
;
830 s
->next_locty
= TPM_TIS_NO_LOCALITY
;
831 s
->aborting_locty
= TPM_TIS_NO_LOCALITY
;
833 for (c
= 0; c
< TPM_TIS_NUM_LOCALITIES
; c
++) {
834 s
->loc
[c
].access
= TPM_TIS_ACCESS_TPM_REG_VALID_STS
;
835 switch (s
->be_tpm_version
) {
836 case TPM_VERSION_UNSPEC
:
838 case TPM_VERSION_1_2
:
839 s
->loc
[c
].sts
= TPM_TIS_STS_TPM_FAMILY1_2
;
840 s
->loc
[c
].iface_id
= TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3
;
842 case TPM_VERSION_2_0
:
843 s
->loc
[c
].sts
= TPM_TIS_STS_TPM_FAMILY2_0
;
844 s
->loc
[c
].iface_id
= TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0
;
847 s
->loc
[c
].inte
= TPM_TIS_INT_POLARITY_LOW_LEVEL
;
849 s
->loc
[c
].state
= TPM_TIS_STATE_IDLE
;
854 if (tpm_backend_startup_tpm(s
->be_driver
, s
->be_buffer_size
) < 0) {
859 /* persistent state handling */
861 int tpm_tis_pre_save(TPMState
*s
)
863 uint8_t locty
= s
->active_locty
;
865 trace_tpm_tis_pre_save(locty
, s
->rw_offset
);
868 tpm_tis_dump_state(s
, 0);
872 * Synchronize with backend completion.
874 tpm_backend_finish_sync(s
->be_driver
);
879 const VMStateDescription vmstate_locty
= {
880 .name
= "tpm-tis/locty",
882 .fields
= (VMStateField
[]) {
883 VMSTATE_UINT32(state
, TPMLocality
),
884 VMSTATE_UINT32(inte
, TPMLocality
),
885 VMSTATE_UINT32(ints
, TPMLocality
),
886 VMSTATE_UINT8(access
, TPMLocality
),
887 VMSTATE_UINT32(sts
, TPMLocality
),
888 VMSTATE_UINT32(iface_id
, TPMLocality
),
889 VMSTATE_END_OF_LIST(),