13676bc69SStefan Berger /*
23676bc69SStefan Berger * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
33676bc69SStefan Berger *
43676bc69SStefan Berger * PAPR Virtual TPM
53676bc69SStefan Berger *
63676bc69SStefan Berger * Copyright (c) 2015, 2017, 2019 IBM Corporation.
73676bc69SStefan Berger *
83676bc69SStefan Berger * Authors:
93676bc69SStefan Berger * Stefan Berger <stefanb@linux.vnet.ibm.com>
103676bc69SStefan Berger *
113676bc69SStefan Berger * This code is licensed under the GPL version 2 or later. See the
123676bc69SStefan Berger * COPYING file in the top-level directory.
133676bc69SStefan Berger *
143676bc69SStefan Berger */
153676bc69SStefan Berger
163676bc69SStefan Berger #include "qemu/osdep.h"
173676bc69SStefan Berger #include "qemu/error-report.h"
183676bc69SStefan Berger #include "qapi/error.h"
193676bc69SStefan Berger #include "hw/qdev-properties.h"
203676bc69SStefan Berger #include "migration/vmstate.h"
213676bc69SStefan Berger
2232cad1ffSPhilippe Mathieu-Daudé #include "system/tpm_backend.h"
2332cad1ffSPhilippe Mathieu-Daudé #include "system/tpm_util.h"
24a3500613SPhilippe Mathieu-Daudé #include "tpm_prop.h"
253676bc69SStefan Berger
263676bc69SStefan Berger #include "hw/ppc/spapr.h"
273676bc69SStefan Berger #include "hw/ppc/spapr_vio.h"
283676bc69SStefan Berger #include "trace.h"
29db1015e9SEduardo Habkost #include "qom/object.h"
303676bc69SStefan Berger
313676bc69SStefan Berger #define DEBUG_SPAPR 0
323676bc69SStefan Berger
33db1015e9SEduardo Habkost typedef struct SpaprTpmState SpaprTpmState;
348110fa1dSEduardo Habkost DECLARE_INSTANCE_CHECKER(SpaprTpmState, VIO_SPAPR_VTPM,
358110fa1dSEduardo Habkost TYPE_TPM_SPAPR)
363676bc69SStefan Berger
373676bc69SStefan Berger typedef struct TpmCrq {
383676bc69SStefan Berger uint8_t valid; /* 0x80: cmd; 0xc0: init crq */
393676bc69SStefan Berger /* 0x81-0x83: CRQ message response */
403676bc69SStefan Berger uint8_t msg; /* see below */
413676bc69SStefan Berger uint16_t len; /* len of TPM request; len of TPM response */
423676bc69SStefan Berger uint32_t data; /* rtce_dma_handle when sending TPM request */
433676bc69SStefan Berger uint64_t reserved;
443676bc69SStefan Berger } TpmCrq;
453676bc69SStefan Berger
463676bc69SStefan Berger #define SPAPR_VTPM_VALID_INIT_CRQ_COMMAND 0xC0
473676bc69SStefan Berger #define SPAPR_VTPM_VALID_COMMAND 0x80
483676bc69SStefan Berger #define SPAPR_VTPM_MSG_RESULT 0x80
493676bc69SStefan Berger
503676bc69SStefan Berger /* msg types for valid = SPAPR_VTPM_VALID_INIT_CRQ */
513676bc69SStefan Berger #define SPAPR_VTPM_INIT_CRQ_RESULT 0x1
523676bc69SStefan Berger #define SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT 0x2
533676bc69SStefan Berger
543676bc69SStefan Berger /* msg types for valid = SPAPR_VTPM_VALID_CMD */
553676bc69SStefan Berger #define SPAPR_VTPM_GET_VERSION 0x1
563676bc69SStefan Berger #define SPAPR_VTPM_TPM_COMMAND 0x2
573676bc69SStefan Berger #define SPAPR_VTPM_GET_RTCE_BUFFER_SIZE 0x3
583676bc69SStefan Berger #define SPAPR_VTPM_PREPARE_TO_SUSPEND 0x4
593676bc69SStefan Berger
603676bc69SStefan Berger /* response error messages */
613676bc69SStefan Berger #define SPAPR_VTPM_VTPM_ERROR 0xff
623676bc69SStefan Berger
633676bc69SStefan Berger /* error codes */
643676bc69SStefan Berger #define SPAPR_VTPM_ERR_COPY_IN_FAILED 0x3
653676bc69SStefan Berger #define SPAPR_VTPM_ERR_COPY_OUT_FAILED 0x4
663676bc69SStefan Berger
673676bc69SStefan Berger #define TPM_SPAPR_BUFFER_MAX 4096
683676bc69SStefan Berger
69db1015e9SEduardo Habkost struct SpaprTpmState {
703676bc69SStefan Berger SpaprVioDevice vdev;
713676bc69SStefan Berger
723676bc69SStefan Berger TpmCrq crq; /* track single TPM command */
733676bc69SStefan Berger
743676bc69SStefan Berger uint8_t state;
753676bc69SStefan Berger #define SPAPR_VTPM_STATE_NONE 0
763676bc69SStefan Berger #define SPAPR_VTPM_STATE_EXECUTION 1
773676bc69SStefan Berger #define SPAPR_VTPM_STATE_COMPLETION 2
783676bc69SStefan Berger
793676bc69SStefan Berger unsigned char *buffer;
803676bc69SStefan Berger
81ee9a8129SStefan Berger uint32_t numbytes; /* number of bytes to deliver on resume */
82ee9a8129SStefan Berger
833676bc69SStefan Berger TPMBackendCmd cmd;
843676bc69SStefan Berger
853676bc69SStefan Berger TPMBackend *be_driver;
863676bc69SStefan Berger TPMVersion be_tpm_version;
873676bc69SStefan Berger
883676bc69SStefan Berger size_t be_buffer_size;
89db1015e9SEduardo Habkost };
903676bc69SStefan Berger
913676bc69SStefan Berger /*
923676bc69SStefan Berger * Send a request to the TPM.
933676bc69SStefan Berger */
tpm_spapr_tpm_send(SpaprTpmState * s)943676bc69SStefan Berger static void tpm_spapr_tpm_send(SpaprTpmState *s)
953676bc69SStefan Berger {
963676bc69SStefan Berger tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM");
973676bc69SStefan Berger
983676bc69SStefan Berger s->state = SPAPR_VTPM_STATE_EXECUTION;
993676bc69SStefan Berger s->cmd = (TPMBackendCmd) {
1003676bc69SStefan Berger .locty = 0,
1013676bc69SStefan Berger .in = s->buffer,
1023676bc69SStefan Berger .in_len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size),
1033676bc69SStefan Berger .out = s->buffer,
1043676bc69SStefan Berger .out_len = s->be_buffer_size,
1053676bc69SStefan Berger };
1063676bc69SStefan Berger
1073676bc69SStefan Berger tpm_backend_deliver_request(s->be_driver, &s->cmd);
1083676bc69SStefan Berger }
1093676bc69SStefan Berger
tpm_spapr_process_cmd(SpaprTpmState * s,uint64_t dataptr)1103676bc69SStefan Berger static int tpm_spapr_process_cmd(SpaprTpmState *s, uint64_t dataptr)
1113676bc69SStefan Berger {
1123676bc69SStefan Berger long rc;
1133676bc69SStefan Berger
1143676bc69SStefan Berger /* a max. of be_buffer_size bytes can be transported */
1153676bc69SStefan Berger rc = spapr_vio_dma_read(&s->vdev, dataptr,
1163676bc69SStefan Berger s->buffer, s->be_buffer_size);
1173676bc69SStefan Berger if (rc) {
1183676bc69SStefan Berger error_report("tpm_spapr_got_payload: DMA read failure");
1193676bc69SStefan Berger }
1203676bc69SStefan Berger /* let vTPM handle any malformed request */
1213676bc69SStefan Berger tpm_spapr_tpm_send(s);
1223676bc69SStefan Berger
1233676bc69SStefan Berger return rc;
1243676bc69SStefan Berger }
1253676bc69SStefan Berger
spapr_tpm_send_crq(struct SpaprVioDevice * dev,TpmCrq * crq)1263676bc69SStefan Berger static inline int spapr_tpm_send_crq(struct SpaprVioDevice *dev, TpmCrq *crq)
1273676bc69SStefan Berger {
1283676bc69SStefan Berger return spapr_vio_send_crq(dev, (uint8_t *)crq);
1293676bc69SStefan Berger }
1303676bc69SStefan Berger
tpm_spapr_do_crq(struct SpaprVioDevice * dev,uint8_t * crq_data)1313676bc69SStefan Berger static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data)
1323676bc69SStefan Berger {
1333676bc69SStefan Berger SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
1343676bc69SStefan Berger TpmCrq local_crq;
1353676bc69SStefan Berger TpmCrq *crq = &s->crq; /* requests only */
1363676bc69SStefan Berger int rc;
1373676bc69SStefan Berger uint8_t valid = crq_data[0];
1383676bc69SStefan Berger uint8_t msg = crq_data[1];
1393676bc69SStefan Berger
1403676bc69SStefan Berger trace_tpm_spapr_do_crq(valid, msg);
1413676bc69SStefan Berger
1423676bc69SStefan Berger switch (valid) {
1433676bc69SStefan Berger case SPAPR_VTPM_VALID_INIT_CRQ_COMMAND: /* Init command/response */
1443676bc69SStefan Berger
1453676bc69SStefan Berger /* Respond to initialization request */
1463676bc69SStefan Berger switch (msg) {
1473676bc69SStefan Berger case SPAPR_VTPM_INIT_CRQ_RESULT:
1483676bc69SStefan Berger trace_tpm_spapr_do_crq_crq_result();
1493676bc69SStefan Berger memset(&local_crq, 0, sizeof(local_crq));
1503676bc69SStefan Berger local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND;
1513676bc69SStefan Berger local_crq.msg = SPAPR_VTPM_INIT_CRQ_RESULT;
1523676bc69SStefan Berger spapr_tpm_send_crq(dev, &local_crq);
1533676bc69SStefan Berger break;
1543676bc69SStefan Berger
1553676bc69SStefan Berger case SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT:
1563676bc69SStefan Berger trace_tpm_spapr_do_crq_crq_complete_result();
1573676bc69SStefan Berger memset(&local_crq, 0, sizeof(local_crq));
1583676bc69SStefan Berger local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND;
1593676bc69SStefan Berger local_crq.msg = SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT;
1603676bc69SStefan Berger spapr_tpm_send_crq(dev, &local_crq);
1613676bc69SStefan Berger break;
1623676bc69SStefan Berger }
1633676bc69SStefan Berger
1643676bc69SStefan Berger break;
1653676bc69SStefan Berger case SPAPR_VTPM_VALID_COMMAND: /* Payloads */
1663676bc69SStefan Berger switch (msg) {
1673676bc69SStefan Berger case SPAPR_VTPM_TPM_COMMAND:
1683676bc69SStefan Berger trace_tpm_spapr_do_crq_tpm_command();
1693676bc69SStefan Berger if (s->state == SPAPR_VTPM_STATE_EXECUTION) {
1703676bc69SStefan Berger return H_BUSY;
1713676bc69SStefan Berger }
1723676bc69SStefan Berger memcpy(crq, crq_data, sizeof(*crq));
1733676bc69SStefan Berger
1743676bc69SStefan Berger rc = tpm_spapr_process_cmd(s, be32_to_cpu(crq->data));
1753676bc69SStefan Berger
1763676bc69SStefan Berger if (rc == H_SUCCESS) {
1773676bc69SStefan Berger crq->valid = be16_to_cpu(0);
1783676bc69SStefan Berger } else {
1793676bc69SStefan Berger local_crq.valid = SPAPR_VTPM_MSG_RESULT;
1803676bc69SStefan Berger local_crq.msg = SPAPR_VTPM_VTPM_ERROR;
1813676bc69SStefan Berger local_crq.len = cpu_to_be16(0);
1823676bc69SStefan Berger local_crq.data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_IN_FAILED);
1833676bc69SStefan Berger spapr_tpm_send_crq(dev, &local_crq);
1843676bc69SStefan Berger }
1853676bc69SStefan Berger break;
1863676bc69SStefan Berger
1873676bc69SStefan Berger case SPAPR_VTPM_GET_RTCE_BUFFER_SIZE:
1883676bc69SStefan Berger trace_tpm_spapr_do_crq_tpm_get_rtce_buffer_size(s->be_buffer_size);
1893676bc69SStefan Berger local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
1903676bc69SStefan Berger local_crq.msg = SPAPR_VTPM_GET_RTCE_BUFFER_SIZE |
1913676bc69SStefan Berger SPAPR_VTPM_MSG_RESULT;
1923676bc69SStefan Berger local_crq.len = cpu_to_be16(s->be_buffer_size);
1933676bc69SStefan Berger spapr_tpm_send_crq(dev, &local_crq);
1943676bc69SStefan Berger break;
1953676bc69SStefan Berger
1963676bc69SStefan Berger case SPAPR_VTPM_GET_VERSION:
1973676bc69SStefan Berger local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
1983676bc69SStefan Berger local_crq.msg = SPAPR_VTPM_GET_VERSION | SPAPR_VTPM_MSG_RESULT;
1993676bc69SStefan Berger local_crq.len = cpu_to_be16(0);
2003676bc69SStefan Berger switch (s->be_tpm_version) {
2013676bc69SStefan Berger case TPM_VERSION_1_2:
2023676bc69SStefan Berger local_crq.data = cpu_to_be32(1);
2033676bc69SStefan Berger break;
2043676bc69SStefan Berger case TPM_VERSION_2_0:
2053676bc69SStefan Berger local_crq.data = cpu_to_be32(2);
2063676bc69SStefan Berger break;
2073676bc69SStefan Berger default:
2083676bc69SStefan Berger g_assert_not_reached();
2093676bc69SStefan Berger }
2103676bc69SStefan Berger trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data));
2113676bc69SStefan Berger spapr_tpm_send_crq(dev, &local_crq);
2123676bc69SStefan Berger break;
2133676bc69SStefan Berger
2143676bc69SStefan Berger case SPAPR_VTPM_PREPARE_TO_SUSPEND:
2153676bc69SStefan Berger trace_tpm_spapr_do_crq_prepare_to_suspend();
2163676bc69SStefan Berger local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
2173676bc69SStefan Berger local_crq.msg = SPAPR_VTPM_PREPARE_TO_SUSPEND |
2183676bc69SStefan Berger SPAPR_VTPM_MSG_RESULT;
2193676bc69SStefan Berger spapr_tpm_send_crq(dev, &local_crq);
2203676bc69SStefan Berger break;
2213676bc69SStefan Berger
2223676bc69SStefan Berger default:
2233676bc69SStefan Berger trace_tpm_spapr_do_crq_unknown_msg_type(crq->msg);
2243676bc69SStefan Berger }
2253676bc69SStefan Berger break;
2263676bc69SStefan Berger default:
2273676bc69SStefan Berger trace_tpm_spapr_do_crq_unknown_crq(valid, msg);
2283676bc69SStefan Berger };
2293676bc69SStefan Berger
2303676bc69SStefan Berger return H_SUCCESS;
2313676bc69SStefan Berger }
2323676bc69SStefan Berger
tpm_spapr_request_completed(TPMIf * ti,int ret)2333676bc69SStefan Berger static void tpm_spapr_request_completed(TPMIf *ti, int ret)
2343676bc69SStefan Berger {
2353676bc69SStefan Berger SpaprTpmState *s = VIO_SPAPR_VTPM(ti);
2363676bc69SStefan Berger TpmCrq *crq = &s->crq;
2373676bc69SStefan Berger uint32_t len;
2383676bc69SStefan Berger int rc;
2393676bc69SStefan Berger
2403676bc69SStefan Berger s->state = SPAPR_VTPM_STATE_COMPLETION;
2413676bc69SStefan Berger
2423676bc69SStefan Berger /* a max. of be_buffer_size bytes can be transported */
2433676bc69SStefan Berger len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size);
244ee9a8129SStefan Berger
245ee9a8129SStefan Berger if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
246ee9a8129SStefan Berger trace_tpm_spapr_caught_response(len);
247ee9a8129SStefan Berger /* defer delivery of response until .post_load */
248ee9a8129SStefan Berger s->numbytes = len;
249ee9a8129SStefan Berger return;
250ee9a8129SStefan Berger }
251ee9a8129SStefan Berger
2523676bc69SStefan Berger rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data),
2533676bc69SStefan Berger s->buffer, len);
2543676bc69SStefan Berger
2553676bc69SStefan Berger tpm_util_show_buffer(s->buffer, len, "From TPM");
2563676bc69SStefan Berger
2573676bc69SStefan Berger crq->valid = SPAPR_VTPM_MSG_RESULT;
2583676bc69SStefan Berger if (rc == H_SUCCESS) {
2593676bc69SStefan Berger crq->msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT;
2603676bc69SStefan Berger crq->len = cpu_to_be16(len);
2613676bc69SStefan Berger } else {
2623676bc69SStefan Berger error_report("%s: DMA write failure", __func__);
2633676bc69SStefan Berger crq->msg = SPAPR_VTPM_VTPM_ERROR;
2643676bc69SStefan Berger crq->len = cpu_to_be16(0);
2653676bc69SStefan Berger crq->data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_OUT_FAILED);
2663676bc69SStefan Berger }
2673676bc69SStefan Berger
2683676bc69SStefan Berger rc = spapr_tpm_send_crq(&s->vdev, crq);
2693676bc69SStefan Berger if (rc) {
2703676bc69SStefan Berger error_report("%s: Error sending response", __func__);
2713676bc69SStefan Berger }
2723676bc69SStefan Berger }
2733676bc69SStefan Berger
tpm_spapr_do_startup_tpm(SpaprTpmState * s,size_t buffersize)2743676bc69SStefan Berger static int tpm_spapr_do_startup_tpm(SpaprTpmState *s, size_t buffersize)
2753676bc69SStefan Berger {
2763676bc69SStefan Berger return tpm_backend_startup_tpm(s->be_driver, buffersize);
2773676bc69SStefan Berger }
2783676bc69SStefan Berger
tpm_spapr_get_dt_compatible(SpaprVioDevice * dev)2793676bc69SStefan Berger static const char *tpm_spapr_get_dt_compatible(SpaprVioDevice *dev)
2803676bc69SStefan Berger {
2813676bc69SStefan Berger SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
2823676bc69SStefan Berger
2833676bc69SStefan Berger switch (s->be_tpm_version) {
2843676bc69SStefan Berger case TPM_VERSION_1_2:
2853676bc69SStefan Berger return "IBM,vtpm";
2863676bc69SStefan Berger case TPM_VERSION_2_0:
2873676bc69SStefan Berger return "IBM,vtpm20";
2883676bc69SStefan Berger default:
2893676bc69SStefan Berger g_assert_not_reached();
2903676bc69SStefan Berger }
2913676bc69SStefan Berger }
2923676bc69SStefan Berger
tpm_spapr_reset(SpaprVioDevice * dev)2933676bc69SStefan Berger static void tpm_spapr_reset(SpaprVioDevice *dev)
2943676bc69SStefan Berger {
2953676bc69SStefan Berger SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
2963676bc69SStefan Berger
2973676bc69SStefan Berger s->state = SPAPR_VTPM_STATE_NONE;
298ee9a8129SStefan Berger s->numbytes = 0;
2993676bc69SStefan Berger
3003676bc69SStefan Berger s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
3013676bc69SStefan Berger
3023676bc69SStefan Berger s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
3033676bc69SStefan Berger TPM_SPAPR_BUFFER_MAX);
3043676bc69SStefan Berger
3053676bc69SStefan Berger tpm_backend_reset(s->be_driver);
306f8b332a1SStefan Berger
307f8b332a1SStefan Berger if (tpm_spapr_do_startup_tpm(s, s->be_buffer_size) < 0) {
308f8b332a1SStefan Berger exit(1);
309f8b332a1SStefan Berger }
3103676bc69SStefan Berger }
3113676bc69SStefan Berger
tpm_spapr_get_version(TPMIf * ti)3123676bc69SStefan Berger static enum TPMVersion tpm_spapr_get_version(TPMIf *ti)
3133676bc69SStefan Berger {
3143676bc69SStefan Berger SpaprTpmState *s = VIO_SPAPR_VTPM(ti);
3153676bc69SStefan Berger
3163676bc69SStefan Berger if (tpm_backend_had_startup_error(s->be_driver)) {
3173676bc69SStefan Berger return TPM_VERSION_UNSPEC;
3183676bc69SStefan Berger }
3193676bc69SStefan Berger
3203676bc69SStefan Berger return tpm_backend_get_tpm_version(s->be_driver);
3213676bc69SStefan Berger }
3223676bc69SStefan Berger
323ee9a8129SStefan Berger /* persistent state handling */
324ee9a8129SStefan Berger
tpm_spapr_pre_save(void * opaque)325ee9a8129SStefan Berger static int tpm_spapr_pre_save(void *opaque)
326ee9a8129SStefan Berger {
327ee9a8129SStefan Berger SpaprTpmState *s = opaque;
328ee9a8129SStefan Berger
329ee9a8129SStefan Berger tpm_backend_finish_sync(s->be_driver);
330ee9a8129SStefan Berger /*
331ee9a8129SStefan Berger * we cannot deliver the results to the VM since DMA would touch VM memory
332ee9a8129SStefan Berger */
333ee9a8129SStefan Berger
334ee9a8129SStefan Berger return 0;
335ee9a8129SStefan Berger }
336ee9a8129SStefan Berger
tpm_spapr_post_load(void * opaque,int version_id)337ee9a8129SStefan Berger static int tpm_spapr_post_load(void *opaque, int version_id)
338ee9a8129SStefan Berger {
339ee9a8129SStefan Berger SpaprTpmState *s = opaque;
340ee9a8129SStefan Berger
341ee9a8129SStefan Berger if (s->numbytes) {
342ee9a8129SStefan Berger trace_tpm_spapr_post_load();
343ee9a8129SStefan Berger /* deliver the results to the VM via DMA */
344ee9a8129SStefan Berger tpm_spapr_request_completed(TPM_IF(s), 0);
345ee9a8129SStefan Berger s->numbytes = 0;
346ee9a8129SStefan Berger }
347ee9a8129SStefan Berger
348ee9a8129SStefan Berger return 0;
349ee9a8129SStefan Berger }
350ee9a8129SStefan Berger
3513676bc69SStefan Berger static const VMStateDescription vmstate_spapr_vtpm = {
3523676bc69SStefan Berger .name = "tpm-spapr",
353ee9a8129SStefan Berger .pre_save = tpm_spapr_pre_save,
354ee9a8129SStefan Berger .post_load = tpm_spapr_post_load,
3555e6aceb2SRichard Henderson .fields = (const VMStateField[]) {
356ee9a8129SStefan Berger VMSTATE_SPAPR_VIO(vdev, SpaprTpmState),
357ee9a8129SStefan Berger
358ee9a8129SStefan Berger VMSTATE_UINT8(state, SpaprTpmState),
359ee9a8129SStefan Berger VMSTATE_UINT32(numbytes, SpaprTpmState),
360ee9a8129SStefan Berger VMSTATE_VBUFFER_UINT32(buffer, SpaprTpmState, 0, NULL, numbytes),
361ee9a8129SStefan Berger /* remember DMA address */
362ee9a8129SStefan Berger VMSTATE_UINT32(crq.data, SpaprTpmState),
363ee9a8129SStefan Berger VMSTATE_END_OF_LIST(),
364ee9a8129SStefan Berger }
3653676bc69SStefan Berger };
3663676bc69SStefan Berger
3673885fa15SRichard Henderson static const Property tpm_spapr_properties[] = {
3683676bc69SStefan Berger DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev),
3693676bc69SStefan Berger DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver),
3703676bc69SStefan Berger };
3713676bc69SStefan Berger
tpm_spapr_realizefn(SpaprVioDevice * dev,Error ** errp)3723676bc69SStefan Berger static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp)
3733676bc69SStefan Berger {
3743676bc69SStefan Berger SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
3753676bc69SStefan Berger
3763676bc69SStefan Berger if (!tpm_find()) {
3773676bc69SStefan Berger error_setg(errp, "at most one TPM device is permitted");
3783676bc69SStefan Berger return;
3793676bc69SStefan Berger }
3803676bc69SStefan Berger
3813676bc69SStefan Berger dev->crq.SendFunc = tpm_spapr_do_crq;
3823676bc69SStefan Berger
3833676bc69SStefan Berger if (!s->be_driver) {
3843676bc69SStefan Berger error_setg(errp, "'tpmdev' property is required");
3853676bc69SStefan Berger return;
3863676bc69SStefan Berger }
3873676bc69SStefan Berger s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX);
3883676bc69SStefan Berger }
3893676bc69SStefan Berger
tpm_spapr_class_init(ObjectClass * klass,const void * data)39012d1a768SPhilippe Mathieu-Daudé static void tpm_spapr_class_init(ObjectClass *klass, const void *data)
3913676bc69SStefan Berger {
3923676bc69SStefan Berger DeviceClass *dc = DEVICE_CLASS(klass);
3933676bc69SStefan Berger SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
3943676bc69SStefan Berger TPMIfClass *tc = TPM_IF_CLASS(klass);
3953676bc69SStefan Berger
3963676bc69SStefan Berger k->realize = tpm_spapr_realizefn;
3973676bc69SStefan Berger k->reset = tpm_spapr_reset;
3983676bc69SStefan Berger k->dt_name = "vtpm";
3993676bc69SStefan Berger k->dt_type = "IBM,vtpm";
4003676bc69SStefan Berger k->get_dt_compatible = tpm_spapr_get_dt_compatible;
4013676bc69SStefan Berger k->signal_mask = 0x00000001;
4023676bc69SStefan Berger set_bit(DEVICE_CATEGORY_MISC, dc->categories);
4033676bc69SStefan Berger device_class_set_props(dc, tpm_spapr_properties);
4043676bc69SStefan Berger k->rtce_window_size = 0x10000000;
4053676bc69SStefan Berger dc->vmsd = &vmstate_spapr_vtpm;
4063676bc69SStefan Berger
4073676bc69SStefan Berger tc->model = TPM_MODEL_TPM_SPAPR;
4083676bc69SStefan Berger tc->get_version = tpm_spapr_get_version;
4093676bc69SStefan Berger tc->request_completed = tpm_spapr_request_completed;
4103676bc69SStefan Berger }
4113676bc69SStefan Berger
4123676bc69SStefan Berger static const TypeInfo tpm_spapr_info = {
4133676bc69SStefan Berger .name = TYPE_TPM_SPAPR,
4143676bc69SStefan Berger .parent = TYPE_VIO_SPAPR_DEVICE,
4153676bc69SStefan Berger .instance_size = sizeof(SpaprTpmState),
4163676bc69SStefan Berger .class_init = tpm_spapr_class_init,
417*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) {
4183676bc69SStefan Berger { TYPE_TPM_IF },
4193676bc69SStefan Berger { }
4203676bc69SStefan Berger }
4213676bc69SStefan Berger };
4223676bc69SStefan Berger
tpm_spapr_register_types(void)4233676bc69SStefan Berger static void tpm_spapr_register_types(void)
4243676bc69SStefan Berger {
4253676bc69SStefan Berger type_register_static(&tpm_spapr_info);
4263676bc69SStefan Berger }
4273676bc69SStefan Berger
4283676bc69SStefan Berger type_init(tpm_spapr_register_types)
429