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/module.h"
31 #include "hw/acpi/tpm.h"
32 #include "hw/pci/pci_ids.h"
33 #include "hw/qdev-properties.h"
34 #include "migration/vmstate.h"
35 #include "sysemu/tpm_backend.h"
36 #include "sysemu/tpm_util.h"
44 /* local prototypes */
46 static uint64_t tpm_tis_mmio_read(void *opaque
, hwaddr addr
,
49 /* utility functions */
51 static uint8_t tpm_tis_locality_from_addr(hwaddr addr
)
55 locty
= (uint8_t)((addr
>> TPM_TIS_LOCALITY_SHIFT
) & 0x7);
56 assert(TPM_TIS_IS_VALID_LOCTY(locty
));
63 * Set the given flags in the STS register by clearing the register but
64 * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting
67 * The SELFTEST_DONE flag is acquired from the backend that determines it by
68 * peeking into TPM commands.
70 * A VM suspend/resume will preserve the flag by storing it into the VM
71 * device state, but the backend will not remember it when QEMU is started
72 * again. Therefore, we cache the flag here. Once set, it will not be unset
75 static void tpm_tis_sts_set(TPMLocality
*l
, uint32_t flags
)
77 l
->sts
&= TPM_TIS_STS_SELFTEST_DONE
| TPM_TIS_STS_TPM_FAMILY_MASK
;
82 * Send a request to the TPM.
84 static void tpm_tis_tpm_send(TPMState
*s
, uint8_t locty
)
86 tpm_util_show_buffer(s
->buffer
, s
->be_buffer_size
, "To TPM");
89 * rw_offset serves as length indicator for length of data;
90 * it's reset when the response comes back
92 s
->loc
[locty
].state
= TPM_TIS_STATE_EXECUTION
;
94 s
->cmd
= (TPMBackendCmd
) {
97 .in_len
= s
->rw_offset
,
99 .out_len
= s
->be_buffer_size
,
102 tpm_backend_deliver_request(s
->be_driver
, &s
->cmd
);
105 /* raise an interrupt if allowed */
106 static void tpm_tis_raise_irq(TPMState
*s
, uint8_t locty
, uint32_t irqmask
)
108 if (!TPM_TIS_IS_VALID_LOCTY(locty
)) {
112 if ((s
->loc
[locty
].inte
& TPM_TIS_INT_ENABLED
) &&
113 (s
->loc
[locty
].inte
& irqmask
)) {
114 trace_tpm_tis_raise_irq(irqmask
);
115 qemu_irq_raise(s
->irq
);
116 s
->loc
[locty
].ints
|= irqmask
;
120 static uint32_t tpm_tis_check_request_use_except(TPMState
*s
, uint8_t locty
)
124 for (l
= 0; l
< TPM_TIS_NUM_LOCALITIES
; l
++) {
128 if ((s
->loc
[l
].access
& TPM_TIS_ACCESS_REQUEST_USE
)) {
136 static void tpm_tis_new_active_locality(TPMState
*s
, uint8_t new_active_locty
)
138 bool change
= (s
->active_locty
!= new_active_locty
);
142 if (change
&& TPM_TIS_IS_VALID_LOCTY(s
->active_locty
)) {
143 is_seize
= TPM_TIS_IS_VALID_LOCTY(new_active_locty
) &&
144 s
->loc
[new_active_locty
].access
& TPM_TIS_ACCESS_SEIZE
;
147 mask
= ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY
);
149 mask
= ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY
|
150 TPM_TIS_ACCESS_REQUEST_USE
);
152 /* reset flags on the old active locality */
153 s
->loc
[s
->active_locty
].access
&= mask
;
156 s
->loc
[s
->active_locty
].access
|= TPM_TIS_ACCESS_BEEN_SEIZED
;
160 s
->active_locty
= new_active_locty
;
162 trace_tpm_tis_new_active_locality(s
->active_locty
);
164 if (TPM_TIS_IS_VALID_LOCTY(new_active_locty
)) {
165 /* set flags on the new active locality */
166 s
->loc
[new_active_locty
].access
|= TPM_TIS_ACCESS_ACTIVE_LOCALITY
;
167 s
->loc
[new_active_locty
].access
&= ~(TPM_TIS_ACCESS_REQUEST_USE
|
168 TPM_TIS_ACCESS_SEIZE
);
172 tpm_tis_raise_irq(s
, s
->active_locty
, TPM_TIS_INT_LOCALITY_CHANGED
);
176 /* abort -- this function switches the locality */
177 static void tpm_tis_abort(TPMState
*s
)
181 trace_tpm_tis_abort(s
->next_locty
);
184 * Need to react differently depending on who's aborting now and
185 * which locality will become active afterwards.
187 if (s
->aborting_locty
== s
->next_locty
) {
188 s
->loc
[s
->aborting_locty
].state
= TPM_TIS_STATE_READY
;
189 tpm_tis_sts_set(&s
->loc
[s
->aborting_locty
],
190 TPM_TIS_STS_COMMAND_READY
);
191 tpm_tis_raise_irq(s
, s
->aborting_locty
, TPM_TIS_INT_COMMAND_READY
);
194 /* locality after abort is another one than the current one */
195 tpm_tis_new_active_locality(s
, s
->next_locty
);
197 s
->next_locty
= TPM_TIS_NO_LOCALITY
;
198 /* nobody's aborting a command anymore */
199 s
->aborting_locty
= TPM_TIS_NO_LOCALITY
;
202 /* prepare aborting current command */
203 static void tpm_tis_prep_abort(TPMState
*s
, uint8_t locty
, uint8_t newlocty
)
207 assert(TPM_TIS_IS_VALID_LOCTY(newlocty
));
209 s
->aborting_locty
= locty
; /* may also be TPM_TIS_NO_LOCALITY */
210 s
->next_locty
= newlocty
; /* locality after successful abort */
213 * only abort a command using an interrupt if currently executing
214 * a command AND if there's a valid connection to the vTPM.
216 for (busy_locty
= 0; busy_locty
< TPM_TIS_NUM_LOCALITIES
; busy_locty
++) {
217 if (s
->loc
[busy_locty
].state
== TPM_TIS_STATE_EXECUTION
) {
219 * request the backend to cancel. Some backends may not
222 tpm_backend_cancel_cmd(s
->be_driver
);
231 * Callback from the TPM to indicate that the response was received.
233 void tpm_tis_request_completed(TPMState
*s
, int ret
)
235 uint8_t locty
= s
->cmd
.locty
;
238 assert(TPM_TIS_IS_VALID_LOCTY(locty
));
240 if (s
->cmd
.selftest_done
) {
241 for (l
= 0; l
< TPM_TIS_NUM_LOCALITIES
; l
++) {
242 s
->loc
[l
].sts
|= TPM_TIS_STS_SELFTEST_DONE
;
246 /* FIXME: report error if ret != 0 */
247 tpm_tis_sts_set(&s
->loc
[locty
],
248 TPM_TIS_STS_VALID
| TPM_TIS_STS_DATA_AVAILABLE
);
249 s
->loc
[locty
].state
= TPM_TIS_STATE_COMPLETION
;
252 tpm_util_show_buffer(s
->buffer
, s
->be_buffer_size
, "From TPM");
254 if (TPM_TIS_IS_VALID_LOCTY(s
->next_locty
)) {
258 tpm_tis_raise_irq(s
, locty
,
259 TPM_TIS_INT_DATA_AVAILABLE
| TPM_TIS_INT_STS_VALID
);
263 * Read a byte of response data
265 static uint32_t tpm_tis_data_read(TPMState
*s
, uint8_t locty
)
267 uint32_t ret
= TPM_TIS_NO_DATA_BYTE
;
270 if ((s
->loc
[locty
].sts
& TPM_TIS_STS_DATA_AVAILABLE
)) {
271 len
= MIN(tpm_cmd_get_size(&s
->buffer
),
274 ret
= s
->buffer
[s
->rw_offset
++];
275 if (s
->rw_offset
>= len
) {
277 tpm_tis_sts_set(&s
->loc
[locty
], TPM_TIS_STS_VALID
);
278 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_STS_VALID
);
280 trace_tpm_tis_data_read(ret
, s
->rw_offset
- 1);
287 static void tpm_tis_dump_state(TPMState
*s
, hwaddr addr
)
289 static const unsigned regs
[] = {
291 TPM_TIS_REG_INT_ENABLE
,
292 TPM_TIS_REG_INT_VECTOR
,
293 TPM_TIS_REG_INT_STATUS
,
294 TPM_TIS_REG_INTF_CAPABILITY
,
300 uint8_t locty
= tpm_tis_locality_from_addr(addr
);
301 hwaddr base
= addr
& ~0xfff;
303 printf("tpm_tis: active locality : %d\n"
304 "tpm_tis: state of locality %d : %d\n"
305 "tpm_tis: register dump:\n",
307 locty
, s
->loc
[locty
].state
);
309 for (idx
= 0; regs
[idx
] != 0xfff; idx
++) {
310 printf("tpm_tis: 0x%04x : 0x%08x\n", regs
[idx
],
311 (int)tpm_tis_mmio_read(s
, base
+ regs
[idx
], 4));
314 printf("tpm_tis: r/w offset : %d\n"
315 "tpm_tis: result buffer : ",
318 idx
< MIN(tpm_cmd_get_size(&s
->buffer
), s
->be_buffer_size
);
321 s
->rw_offset
== idx
? '>' : ' ',
323 ((idx
& 0xf) == 0xf) ? "\ntpm_tis: " : "");
330 * Read a register of the TIS interface
331 * See specs pages 33-63 for description of the registers
333 static uint64_t tpm_tis_mmio_read(void *opaque
, hwaddr addr
,
336 TPMState
*s
= opaque
;
337 uint16_t offset
= addr
& 0xffc;
338 uint8_t shift
= (addr
& 0x3) * 8;
339 uint32_t val
= 0xffffffff;
340 uint8_t locty
= tpm_tis_locality_from_addr(addr
);
344 if (tpm_backend_had_startup_error(s
->be_driver
)) {
349 case TPM_TIS_REG_ACCESS
:
350 /* never show the SEIZE flag even though we use it internally */
351 val
= s
->loc
[locty
].access
& ~TPM_TIS_ACCESS_SEIZE
;
352 /* the pending flag is always calculated */
353 if (tpm_tis_check_request_use_except(s
, locty
)) {
354 val
|= TPM_TIS_ACCESS_PENDING_REQUEST
;
356 val
|= !tpm_backend_get_tpm_established_flag(s
->be_driver
);
358 case TPM_TIS_REG_INT_ENABLE
:
359 val
= s
->loc
[locty
].inte
;
361 case TPM_TIS_REG_INT_VECTOR
:
364 case TPM_TIS_REG_INT_STATUS
:
365 val
= s
->loc
[locty
].ints
;
367 case TPM_TIS_REG_INTF_CAPABILITY
:
368 switch (s
->be_tpm_version
) {
369 case TPM_VERSION_UNSPEC
:
372 case TPM_VERSION_1_2
:
373 val
= TPM_TIS_CAPABILITIES_SUPPORTED1_3
;
375 case TPM_VERSION_2_0
:
376 val
= TPM_TIS_CAPABILITIES_SUPPORTED2_0
;
380 case TPM_TIS_REG_STS
:
381 if (s
->active_locty
== locty
) {
382 if ((s
->loc
[locty
].sts
& TPM_TIS_STS_DATA_AVAILABLE
)) {
383 val
= TPM_TIS_BURST_COUNT(
384 MIN(tpm_cmd_get_size(&s
->buffer
),
386 - s
->rw_offset
) | s
->loc
[locty
].sts
;
388 avail
= s
->be_buffer_size
- s
->rw_offset
;
390 * byte-sized reads should not return 0x00 for 0x100
393 if (size
== 1 && avail
> 0xff) {
396 val
= TPM_TIS_BURST_COUNT(avail
) | s
->loc
[locty
].sts
;
400 case TPM_TIS_REG_DATA_FIFO
:
401 case TPM_TIS_REG_DATA_XFIFO
... TPM_TIS_REG_DATA_XFIFO_END
:
402 if (s
->active_locty
== locty
) {
403 if (size
> 4 - (addr
& 0x3)) {
404 /* prevent access beyond FIFO */
405 size
= 4 - (addr
& 0x3);
410 switch (s
->loc
[locty
].state
) {
411 case TPM_TIS_STATE_COMPLETION
:
412 v
= tpm_tis_data_read(s
, locty
);
415 v
= TPM_TIS_NO_DATA_BYTE
;
422 shift
= 0; /* no more adjustments */
425 case TPM_TIS_REG_INTERFACE_ID
:
426 val
= s
->loc
[locty
].iface_id
;
428 case TPM_TIS_REG_DID_VID
:
429 val
= (TPM_TIS_TPM_DID
<< 16) | TPM_TIS_TPM_VID
;
431 case TPM_TIS_REG_RID
:
432 val
= TPM_TIS_TPM_RID
;
435 case TPM_TIS_REG_DEBUG
:
436 tpm_tis_dump_state(s
, addr
);
445 trace_tpm_tis_mmio_read(size
, addr
, val
);
451 * Write a value to a register of the TIS interface
452 * See specs pages 33-63 for description of the registers
454 static void tpm_tis_mmio_write(void *opaque
, hwaddr addr
,
455 uint64_t val
, unsigned size
)
457 TPMState
*s
= opaque
;
458 uint16_t off
= addr
& 0xffc;
459 uint8_t shift
= (addr
& 0x3) * 8;
460 uint8_t locty
= tpm_tis_locality_from_addr(addr
);
461 uint8_t active_locty
, l
;
462 int c
, set_new_locty
= 1;
464 uint32_t mask
= (size
== 1) ? 0xff : ((size
== 2) ? 0xffff : ~0);
466 trace_tpm_tis_mmio_write(size
, addr
, val
);
469 trace_tpm_tis_mmio_write_locty4();
473 if (tpm_backend_had_startup_error(s
->be_driver
)) {
487 case TPM_TIS_REG_ACCESS
:
489 if ((val
& TPM_TIS_ACCESS_SEIZE
)) {
490 val
&= ~(TPM_TIS_ACCESS_REQUEST_USE
|
491 TPM_TIS_ACCESS_ACTIVE_LOCALITY
);
494 active_locty
= s
->active_locty
;
496 if ((val
& TPM_TIS_ACCESS_ACTIVE_LOCALITY
)) {
497 /* give up locality if currently owned */
498 if (s
->active_locty
== locty
) {
499 trace_tpm_tis_mmio_write_release_locty(locty
);
501 uint8_t newlocty
= TPM_TIS_NO_LOCALITY
;
502 /* anybody wants the locality ? */
503 for (c
= TPM_TIS_NUM_LOCALITIES
- 1; c
>= 0; c
--) {
504 if ((s
->loc
[c
].access
& TPM_TIS_ACCESS_REQUEST_USE
)) {
505 trace_tpm_tis_mmio_write_locty_req_use(c
);
510 trace_tpm_tis_mmio_write_next_locty(newlocty
);
512 if (TPM_TIS_IS_VALID_LOCTY(newlocty
)) {
514 tpm_tis_prep_abort(s
, locty
, newlocty
);
516 active_locty
= TPM_TIS_NO_LOCALITY
;
519 /* not currently the owner; clear a pending request */
520 s
->loc
[locty
].access
&= ~TPM_TIS_ACCESS_REQUEST_USE
;
524 if ((val
& TPM_TIS_ACCESS_BEEN_SEIZED
)) {
525 s
->loc
[locty
].access
&= ~TPM_TIS_ACCESS_BEEN_SEIZED
;
528 if ((val
& TPM_TIS_ACCESS_SEIZE
)) {
530 * allow seize if a locality is active and the requesting
531 * locality is higher than the one that's active
533 * allow seize for requesting locality if no locality is
536 while ((TPM_TIS_IS_VALID_LOCTY(s
->active_locty
) &&
537 locty
> s
->active_locty
) ||
538 !TPM_TIS_IS_VALID_LOCTY(s
->active_locty
)) {
539 bool higher_seize
= false;
541 /* already a pending SEIZE ? */
542 if ((s
->loc
[locty
].access
& TPM_TIS_ACCESS_SEIZE
)) {
546 /* check for ongoing seize by a higher locality */
547 for (l
= locty
+ 1; l
< TPM_TIS_NUM_LOCALITIES
; l
++) {
548 if ((s
->loc
[l
].access
& TPM_TIS_ACCESS_SEIZE
)) {
558 /* cancel any seize by a lower locality */
559 for (l
= 0; l
< locty
; l
++) {
560 s
->loc
[l
].access
&= ~TPM_TIS_ACCESS_SEIZE
;
563 s
->loc
[locty
].access
|= TPM_TIS_ACCESS_SEIZE
;
565 trace_tpm_tis_mmio_write_locty_seized(locty
, s
->active_locty
);
566 trace_tpm_tis_mmio_write_init_abort();
569 tpm_tis_prep_abort(s
, s
->active_locty
, locty
);
574 if ((val
& TPM_TIS_ACCESS_REQUEST_USE
)) {
575 if (s
->active_locty
!= locty
) {
576 if (TPM_TIS_IS_VALID_LOCTY(s
->active_locty
)) {
577 s
->loc
[locty
].access
|= TPM_TIS_ACCESS_REQUEST_USE
;
579 /* no locality active -> make this one active now */
580 active_locty
= locty
;
586 tpm_tis_new_active_locality(s
, active_locty
);
590 case TPM_TIS_REG_INT_ENABLE
:
591 if (s
->active_locty
!= locty
) {
595 s
->loc
[locty
].inte
&= mask
;
596 s
->loc
[locty
].inte
|= (val
& (TPM_TIS_INT_ENABLED
|
597 TPM_TIS_INT_POLARITY_MASK
|
598 TPM_TIS_INTERRUPTS_SUPPORTED
));
600 case TPM_TIS_REG_INT_VECTOR
:
601 /* hard wired -- ignore */
603 case TPM_TIS_REG_INT_STATUS
:
604 if (s
->active_locty
!= locty
) {
608 /* clearing of interrupt flags */
609 if (((val
& TPM_TIS_INTERRUPTS_SUPPORTED
)) &&
610 (s
->loc
[locty
].ints
& TPM_TIS_INTERRUPTS_SUPPORTED
)) {
611 s
->loc
[locty
].ints
&= ~val
;
612 if (s
->loc
[locty
].ints
== 0) {
613 qemu_irq_lower(s
->irq
);
614 trace_tpm_tis_mmio_write_lowering_irq();
617 s
->loc
[locty
].ints
&= ~(val
& TPM_TIS_INTERRUPTS_SUPPORTED
);
619 case TPM_TIS_REG_STS
:
620 if (s
->active_locty
!= locty
) {
624 if (s
->be_tpm_version
== TPM_VERSION_2_0
) {
625 /* some flags that are only supported for TPM 2 */
626 if (val
& TPM_TIS_STS_COMMAND_CANCEL
) {
627 if (s
->loc
[locty
].state
== TPM_TIS_STATE_EXECUTION
) {
629 * request the backend to cancel. Some backends may not
632 tpm_backend_cancel_cmd(s
->be_driver
);
636 if (val
& TPM_TIS_STS_RESET_ESTABLISHMENT_BIT
) {
637 if (locty
== 3 || locty
== 4) {
638 tpm_backend_reset_tpm_established_flag(s
->be_driver
, locty
);
643 val
&= (TPM_TIS_STS_COMMAND_READY
| TPM_TIS_STS_TPM_GO
|
644 TPM_TIS_STS_RESPONSE_RETRY
);
646 if (val
== TPM_TIS_STS_COMMAND_READY
) {
647 switch (s
->loc
[locty
].state
) {
649 case TPM_TIS_STATE_READY
:
653 case TPM_TIS_STATE_IDLE
:
654 tpm_tis_sts_set(&s
->loc
[locty
], TPM_TIS_STS_COMMAND_READY
);
655 s
->loc
[locty
].state
= TPM_TIS_STATE_READY
;
656 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_COMMAND_READY
);
659 case TPM_TIS_STATE_EXECUTION
:
660 case TPM_TIS_STATE_RECEPTION
:
661 /* abort currently running command */
662 trace_tpm_tis_mmio_write_init_abort();
663 tpm_tis_prep_abort(s
, locty
, locty
);
666 case TPM_TIS_STATE_COMPLETION
:
668 /* shortcut to ready state with C/R set */
669 s
->loc
[locty
].state
= TPM_TIS_STATE_READY
;
670 if (!(s
->loc
[locty
].sts
& TPM_TIS_STS_COMMAND_READY
)) {
671 tpm_tis_sts_set(&s
->loc
[locty
],
672 TPM_TIS_STS_COMMAND_READY
);
673 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_COMMAND_READY
);
675 s
->loc
[locty
].sts
&= ~(TPM_TIS_STS_DATA_AVAILABLE
);
679 } else if (val
== TPM_TIS_STS_TPM_GO
) {
680 switch (s
->loc
[locty
].state
) {
681 case TPM_TIS_STATE_RECEPTION
:
682 if ((s
->loc
[locty
].sts
& TPM_TIS_STS_EXPECT
) == 0) {
683 tpm_tis_tpm_send(s
, locty
);
690 } else if (val
== TPM_TIS_STS_RESPONSE_RETRY
) {
691 switch (s
->loc
[locty
].state
) {
692 case TPM_TIS_STATE_COMPLETION
:
694 tpm_tis_sts_set(&s
->loc
[locty
],
696 TPM_TIS_STS_DATA_AVAILABLE
);
704 case TPM_TIS_REG_DATA_FIFO
:
705 case TPM_TIS_REG_DATA_XFIFO
... TPM_TIS_REG_DATA_XFIFO_END
:
707 if (s
->active_locty
!= locty
) {
711 if (s
->loc
[locty
].state
== TPM_TIS_STATE_IDLE
||
712 s
->loc
[locty
].state
== TPM_TIS_STATE_EXECUTION
||
713 s
->loc
[locty
].state
== TPM_TIS_STATE_COMPLETION
) {
716 trace_tpm_tis_mmio_write_data2send(val
, size
);
717 if (s
->loc
[locty
].state
== TPM_TIS_STATE_READY
) {
718 s
->loc
[locty
].state
= TPM_TIS_STATE_RECEPTION
;
719 tpm_tis_sts_set(&s
->loc
[locty
],
720 TPM_TIS_STS_EXPECT
| TPM_TIS_STS_VALID
);
724 if (size
> 4 - (addr
& 0x3)) {
725 /* prevent access beyond FIFO */
726 size
= 4 - (addr
& 0x3);
729 while ((s
->loc
[locty
].sts
& TPM_TIS_STS_EXPECT
) && size
> 0) {
730 if (s
->rw_offset
< s
->be_buffer_size
) {
731 s
->buffer
[s
->rw_offset
++] =
736 tpm_tis_sts_set(&s
->loc
[locty
], TPM_TIS_STS_VALID
);
740 /* check for complete packet */
741 if (s
->rw_offset
> 5 &&
742 (s
->loc
[locty
].sts
& TPM_TIS_STS_EXPECT
)) {
743 /* we have a packet length - see if we have all of it */
744 bool need_irq
= !(s
->loc
[locty
].sts
& TPM_TIS_STS_VALID
);
746 len
= tpm_cmd_get_size(&s
->buffer
);
747 if (len
> s
->rw_offset
) {
748 tpm_tis_sts_set(&s
->loc
[locty
],
749 TPM_TIS_STS_EXPECT
| TPM_TIS_STS_VALID
);
751 /* packet complete */
752 tpm_tis_sts_set(&s
->loc
[locty
], TPM_TIS_STS_VALID
);
755 tpm_tis_raise_irq(s
, locty
, TPM_TIS_INT_STS_VALID
);
760 case TPM_TIS_REG_INTERFACE_ID
:
761 if (val
& TPM_TIS_IFACE_ID_INT_SEL_LOCK
) {
762 for (l
= 0; l
< TPM_TIS_NUM_LOCALITIES
; l
++) {
763 s
->loc
[l
].iface_id
|= TPM_TIS_IFACE_ID_INT_SEL_LOCK
;
770 const MemoryRegionOps tpm_tis_memory_ops
= {
771 .read
= tpm_tis_mmio_read
,
772 .write
= tpm_tis_mmio_write
,
773 .endianness
= DEVICE_LITTLE_ENDIAN
,
775 .min_access_size
= 1,
776 .max_access_size
= 4,
781 * Get the TPMVersion of the backend device being used
783 enum TPMVersion
tpm_tis_get_tpm_version(TPMState
*s
)
785 if (tpm_backend_had_startup_error(s
->be_driver
)) {
786 return TPM_VERSION_UNSPEC
;
789 return tpm_backend_get_tpm_version(s
->be_driver
);
793 * This function is called when the machine starts, resets or due to
796 void tpm_tis_reset(TPMState
*s
)
800 s
->be_tpm_version
= tpm_backend_get_tpm_version(s
->be_driver
);
801 s
->be_buffer_size
= MIN(tpm_backend_get_buffer_size(s
->be_driver
),
804 if (s
->ppi_enabled
) {
805 tpm_ppi_reset(&s
->ppi
);
807 tpm_backend_reset(s
->be_driver
);
809 s
->active_locty
= TPM_TIS_NO_LOCALITY
;
810 s
->next_locty
= TPM_TIS_NO_LOCALITY
;
811 s
->aborting_locty
= TPM_TIS_NO_LOCALITY
;
813 for (c
= 0; c
< TPM_TIS_NUM_LOCALITIES
; c
++) {
814 s
->loc
[c
].access
= TPM_TIS_ACCESS_TPM_REG_VALID_STS
;
815 switch (s
->be_tpm_version
) {
816 case TPM_VERSION_UNSPEC
:
818 case TPM_VERSION_1_2
:
819 s
->loc
[c
].sts
= TPM_TIS_STS_TPM_FAMILY1_2
;
820 s
->loc
[c
].iface_id
= TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3
;
822 case TPM_VERSION_2_0
:
823 s
->loc
[c
].sts
= TPM_TIS_STS_TPM_FAMILY2_0
;
824 s
->loc
[c
].iface_id
= TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0
;
827 s
->loc
[c
].inte
= TPM_TIS_INT_POLARITY_LOW_LEVEL
;
829 s
->loc
[c
].state
= TPM_TIS_STATE_IDLE
;
834 if (tpm_backend_startup_tpm(s
->be_driver
, s
->be_buffer_size
) < 0) {
839 /* persistent state handling */
841 int tpm_tis_pre_save(TPMState
*s
)
843 uint8_t locty
= s
->active_locty
;
845 trace_tpm_tis_pre_save(locty
, s
->rw_offset
);
848 tpm_tis_dump_state(s
, 0);
852 * Synchronize with backend completion.
854 tpm_backend_finish_sync(s
->be_driver
);
859 const VMStateDescription vmstate_locty
= {
860 .name
= "tpm-tis/locty",
862 .fields
= (VMStateField
[]) {
863 VMSTATE_UINT32(state
, TPMLocality
),
864 VMSTATE_UINT32(inte
, TPMLocality
),
865 VMSTATE_UINT32(ints
, TPMLocality
),
866 VMSTATE_UINT8(access
, TPMLocality
),
867 VMSTATE_UINT32(sts
, TPMLocality
),
868 VMSTATE_UINT32(iface_id
, TPMLocality
),
869 VMSTATE_END_OF_LIST(),