xref: /qemu/hw/tpm/tpm_spapr.c (revision ee9a8129d3d975271d4efed1b37b7dac956e7bf5)
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 
223676bc69SStefan Berger #include "sysemu/tpm_backend.h"
233676bc69SStefan Berger #include "tpm_int.h"
243676bc69SStefan Berger #include "tpm_util.h"
253676bc69SStefan Berger 
263676bc69SStefan Berger #include "hw/ppc/spapr.h"
273676bc69SStefan Berger #include "hw/ppc/spapr_vio.h"
283676bc69SStefan Berger #include "trace.h"
293676bc69SStefan Berger 
303676bc69SStefan Berger #define DEBUG_SPAPR 0
313676bc69SStefan Berger 
323676bc69SStefan Berger #define VIO_SPAPR_VTPM(obj) \
333676bc69SStefan Berger      OBJECT_CHECK(SpaprTpmState, (obj), TYPE_TPM_SPAPR)
343676bc69SStefan Berger 
353676bc69SStefan Berger typedef struct TpmCrq {
363676bc69SStefan Berger     uint8_t valid;  /* 0x80: cmd; 0xc0: init crq */
373676bc69SStefan Berger                     /* 0x81-0x83: CRQ message response */
383676bc69SStefan Berger     uint8_t msg;    /* see below */
393676bc69SStefan Berger     uint16_t len;   /* len of TPM request; len of TPM response */
403676bc69SStefan Berger     uint32_t data;  /* rtce_dma_handle when sending TPM request */
413676bc69SStefan Berger     uint64_t reserved;
423676bc69SStefan Berger } TpmCrq;
433676bc69SStefan Berger 
443676bc69SStefan Berger #define SPAPR_VTPM_VALID_INIT_CRQ_COMMAND  0xC0
453676bc69SStefan Berger #define SPAPR_VTPM_VALID_COMMAND           0x80
463676bc69SStefan Berger #define SPAPR_VTPM_MSG_RESULT              0x80
473676bc69SStefan Berger 
483676bc69SStefan Berger /* msg types for valid = SPAPR_VTPM_VALID_INIT_CRQ */
493676bc69SStefan Berger #define SPAPR_VTPM_INIT_CRQ_RESULT           0x1
503676bc69SStefan Berger #define SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT  0x2
513676bc69SStefan Berger 
523676bc69SStefan Berger /* msg types for valid = SPAPR_VTPM_VALID_CMD */
533676bc69SStefan Berger #define SPAPR_VTPM_GET_VERSION               0x1
543676bc69SStefan Berger #define SPAPR_VTPM_TPM_COMMAND               0x2
553676bc69SStefan Berger #define SPAPR_VTPM_GET_RTCE_BUFFER_SIZE      0x3
563676bc69SStefan Berger #define SPAPR_VTPM_PREPARE_TO_SUSPEND        0x4
573676bc69SStefan Berger 
583676bc69SStefan Berger /* response error messages */
593676bc69SStefan Berger #define SPAPR_VTPM_VTPM_ERROR                0xff
603676bc69SStefan Berger 
613676bc69SStefan Berger /* error codes */
623676bc69SStefan Berger #define SPAPR_VTPM_ERR_COPY_IN_FAILED        0x3
633676bc69SStefan Berger #define SPAPR_VTPM_ERR_COPY_OUT_FAILED       0x4
643676bc69SStefan Berger 
653676bc69SStefan Berger #define TPM_SPAPR_BUFFER_MAX                 4096
663676bc69SStefan Berger 
673676bc69SStefan Berger typedef struct {
683676bc69SStefan Berger     SpaprVioDevice vdev;
693676bc69SStefan Berger 
703676bc69SStefan Berger     TpmCrq crq; /* track single TPM command */
713676bc69SStefan Berger 
723676bc69SStefan Berger     uint8_t state;
733676bc69SStefan Berger #define SPAPR_VTPM_STATE_NONE         0
743676bc69SStefan Berger #define SPAPR_VTPM_STATE_EXECUTION    1
753676bc69SStefan Berger #define SPAPR_VTPM_STATE_COMPLETION   2
763676bc69SStefan Berger 
773676bc69SStefan Berger     unsigned char *buffer;
783676bc69SStefan Berger 
79*ee9a8129SStefan Berger     uint32_t numbytes; /* number of bytes to deliver on resume */
80*ee9a8129SStefan Berger 
813676bc69SStefan Berger     TPMBackendCmd cmd;
823676bc69SStefan Berger 
833676bc69SStefan Berger     TPMBackend *be_driver;
843676bc69SStefan Berger     TPMVersion be_tpm_version;
853676bc69SStefan Berger 
863676bc69SStefan Berger     size_t be_buffer_size;
873676bc69SStefan Berger } SpaprTpmState;
883676bc69SStefan Berger 
893676bc69SStefan Berger /*
903676bc69SStefan Berger  * Send a request to the TPM.
913676bc69SStefan Berger  */
923676bc69SStefan Berger static void tpm_spapr_tpm_send(SpaprTpmState *s)
933676bc69SStefan Berger {
943676bc69SStefan Berger     if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) {
953676bc69SStefan Berger         tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM");
963676bc69SStefan Berger     }
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 
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 
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 
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                 break;
2103676bc69SStefan Berger             }
2113676bc69SStefan Berger             trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data));
2123676bc69SStefan Berger             spapr_tpm_send_crq(dev, &local_crq);
2133676bc69SStefan Berger             break;
2143676bc69SStefan Berger 
2153676bc69SStefan Berger         case SPAPR_VTPM_PREPARE_TO_SUSPEND:
2163676bc69SStefan Berger             trace_tpm_spapr_do_crq_prepare_to_suspend();
2173676bc69SStefan Berger             local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
2183676bc69SStefan Berger             local_crq.msg = SPAPR_VTPM_PREPARE_TO_SUSPEND |
2193676bc69SStefan Berger                             SPAPR_VTPM_MSG_RESULT;
2203676bc69SStefan Berger             spapr_tpm_send_crq(dev, &local_crq);
2213676bc69SStefan Berger             break;
2223676bc69SStefan Berger 
2233676bc69SStefan Berger         default:
2243676bc69SStefan Berger             trace_tpm_spapr_do_crq_unknown_msg_type(crq->msg);
2253676bc69SStefan Berger         }
2263676bc69SStefan Berger         break;
2273676bc69SStefan Berger     default:
2283676bc69SStefan Berger         trace_tpm_spapr_do_crq_unknown_crq(valid, msg);
2293676bc69SStefan Berger     };
2303676bc69SStefan Berger 
2313676bc69SStefan Berger     return H_SUCCESS;
2323676bc69SStefan Berger }
2333676bc69SStefan Berger 
2343676bc69SStefan Berger static void tpm_spapr_request_completed(TPMIf *ti, int ret)
2353676bc69SStefan Berger {
2363676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(ti);
2373676bc69SStefan Berger     TpmCrq *crq = &s->crq;
2383676bc69SStefan Berger     uint32_t len;
2393676bc69SStefan Berger     int rc;
2403676bc69SStefan Berger 
2413676bc69SStefan Berger     s->state = SPAPR_VTPM_STATE_COMPLETION;
2423676bc69SStefan Berger 
2433676bc69SStefan Berger     /* a max. of be_buffer_size bytes can be transported */
2443676bc69SStefan Berger     len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size);
245*ee9a8129SStefan Berger 
246*ee9a8129SStefan Berger     if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
247*ee9a8129SStefan Berger         trace_tpm_spapr_caught_response(len);
248*ee9a8129SStefan Berger         /* defer delivery of response until .post_load */
249*ee9a8129SStefan Berger         s->numbytes = len;
250*ee9a8129SStefan Berger         return;
251*ee9a8129SStefan Berger     }
252*ee9a8129SStefan Berger 
2533676bc69SStefan Berger     rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data),
2543676bc69SStefan Berger                              s->buffer, len);
2553676bc69SStefan Berger 
2563676bc69SStefan Berger     if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) {
2573676bc69SStefan Berger         tpm_util_show_buffer(s->buffer, len, "From TPM");
2583676bc69SStefan Berger     }
2593676bc69SStefan Berger 
2603676bc69SStefan Berger     crq->valid = SPAPR_VTPM_MSG_RESULT;
2613676bc69SStefan Berger     if (rc == H_SUCCESS) {
2623676bc69SStefan Berger         crq->msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT;
2633676bc69SStefan Berger         crq->len = cpu_to_be16(len);
2643676bc69SStefan Berger     } else {
2653676bc69SStefan Berger         error_report("%s: DMA write failure", __func__);
2663676bc69SStefan Berger         crq->msg = SPAPR_VTPM_VTPM_ERROR;
2673676bc69SStefan Berger         crq->len = cpu_to_be16(0);
2683676bc69SStefan Berger         crq->data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_OUT_FAILED);
2693676bc69SStefan Berger     }
2703676bc69SStefan Berger 
2713676bc69SStefan Berger     rc = spapr_tpm_send_crq(&s->vdev, crq);
2723676bc69SStefan Berger     if (rc) {
2733676bc69SStefan Berger         error_report("%s: Error sending response", __func__);
2743676bc69SStefan Berger     }
2753676bc69SStefan Berger }
2763676bc69SStefan Berger 
2773676bc69SStefan Berger static int tpm_spapr_do_startup_tpm(SpaprTpmState *s, size_t buffersize)
2783676bc69SStefan Berger {
2793676bc69SStefan Berger     return tpm_backend_startup_tpm(s->be_driver, buffersize);
2803676bc69SStefan Berger }
2813676bc69SStefan Berger 
2823676bc69SStefan Berger static const char *tpm_spapr_get_dt_compatible(SpaprVioDevice *dev)
2833676bc69SStefan Berger {
2843676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
2853676bc69SStefan Berger 
2863676bc69SStefan Berger     switch (s->be_tpm_version) {
2873676bc69SStefan Berger     case TPM_VERSION_1_2:
2883676bc69SStefan Berger         return "IBM,vtpm";
2893676bc69SStefan Berger     case TPM_VERSION_2_0:
2903676bc69SStefan Berger         return "IBM,vtpm20";
2913676bc69SStefan Berger     default:
2923676bc69SStefan Berger         g_assert_not_reached();
2933676bc69SStefan Berger     }
2943676bc69SStefan Berger }
2953676bc69SStefan Berger 
2963676bc69SStefan Berger static void tpm_spapr_reset(SpaprVioDevice *dev)
2973676bc69SStefan Berger {
2983676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
2993676bc69SStefan Berger 
3003676bc69SStefan Berger     s->state = SPAPR_VTPM_STATE_NONE;
301*ee9a8129SStefan Berger     s->numbytes = 0;
3023676bc69SStefan Berger 
3033676bc69SStefan Berger     s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
3043676bc69SStefan Berger 
3053676bc69SStefan Berger     s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
3063676bc69SStefan Berger                             TPM_SPAPR_BUFFER_MAX);
3073676bc69SStefan Berger 
3083676bc69SStefan Berger     tpm_backend_reset(s->be_driver);
3093676bc69SStefan Berger     tpm_spapr_do_startup_tpm(s, s->be_buffer_size);
3103676bc69SStefan Berger }
3113676bc69SStefan Berger 
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 
323*ee9a8129SStefan Berger /* persistent state handling */
324*ee9a8129SStefan Berger 
325*ee9a8129SStefan Berger static int tpm_spapr_pre_save(void *opaque)
326*ee9a8129SStefan Berger {
327*ee9a8129SStefan Berger     SpaprTpmState *s = opaque;
328*ee9a8129SStefan Berger 
329*ee9a8129SStefan Berger     tpm_backend_finish_sync(s->be_driver);
330*ee9a8129SStefan Berger     /*
331*ee9a8129SStefan Berger      * we cannot deliver the results to the VM since DMA would touch VM memory
332*ee9a8129SStefan Berger      */
333*ee9a8129SStefan Berger 
334*ee9a8129SStefan Berger     return 0;
335*ee9a8129SStefan Berger }
336*ee9a8129SStefan Berger 
337*ee9a8129SStefan Berger static int tpm_spapr_post_load(void *opaque, int version_id)
338*ee9a8129SStefan Berger {
339*ee9a8129SStefan Berger     SpaprTpmState *s = opaque;
340*ee9a8129SStefan Berger 
341*ee9a8129SStefan Berger     if (s->numbytes) {
342*ee9a8129SStefan Berger         trace_tpm_spapr_post_load();
343*ee9a8129SStefan Berger         /* deliver the results to the VM via DMA */
344*ee9a8129SStefan Berger         tpm_spapr_request_completed(TPM_IF(s), 0);
345*ee9a8129SStefan Berger         s->numbytes = 0;
346*ee9a8129SStefan Berger     }
347*ee9a8129SStefan Berger 
348*ee9a8129SStefan Berger     return 0;
349*ee9a8129SStefan Berger }
350*ee9a8129SStefan Berger 
3513676bc69SStefan Berger static const VMStateDescription vmstate_spapr_vtpm = {
3523676bc69SStefan Berger     .name = "tpm-spapr",
353*ee9a8129SStefan Berger     .pre_save = tpm_spapr_pre_save,
354*ee9a8129SStefan Berger     .post_load = tpm_spapr_post_load,
355*ee9a8129SStefan Berger     .fields = (VMStateField[]) {
356*ee9a8129SStefan Berger         VMSTATE_SPAPR_VIO(vdev, SpaprTpmState),
357*ee9a8129SStefan Berger 
358*ee9a8129SStefan Berger         VMSTATE_UINT8(state, SpaprTpmState),
359*ee9a8129SStefan Berger         VMSTATE_UINT32(numbytes, SpaprTpmState),
360*ee9a8129SStefan Berger         VMSTATE_VBUFFER_UINT32(buffer, SpaprTpmState, 0, NULL, numbytes),
361*ee9a8129SStefan Berger         /* remember DMA address */
362*ee9a8129SStefan Berger         VMSTATE_UINT32(crq.data, SpaprTpmState),
363*ee9a8129SStefan Berger         VMSTATE_END_OF_LIST(),
364*ee9a8129SStefan Berger     }
3653676bc69SStefan Berger };
3663676bc69SStefan Berger 
3673676bc69SStefan Berger static Property tpm_spapr_properties[] = {
3683676bc69SStefan Berger     DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev),
3693676bc69SStefan Berger     DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver),
3703676bc69SStefan Berger     DEFINE_PROP_END_OF_LIST(),
3713676bc69SStefan Berger };
3723676bc69SStefan Berger 
3733676bc69SStefan Berger static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp)
3743676bc69SStefan Berger {
3753676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
3763676bc69SStefan Berger 
3773676bc69SStefan Berger     if (!tpm_find()) {
3783676bc69SStefan Berger         error_setg(errp, "at most one TPM device is permitted");
3793676bc69SStefan Berger         return;
3803676bc69SStefan Berger     }
3813676bc69SStefan Berger 
3823676bc69SStefan Berger     dev->crq.SendFunc = tpm_spapr_do_crq;
3833676bc69SStefan Berger 
3843676bc69SStefan Berger     if (!s->be_driver) {
3853676bc69SStefan Berger         error_setg(errp, "'tpmdev' property is required");
3863676bc69SStefan Berger         return;
3873676bc69SStefan Berger     }
3883676bc69SStefan Berger     s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX);
3893676bc69SStefan Berger }
3903676bc69SStefan Berger 
3913676bc69SStefan Berger static void tpm_spapr_class_init(ObjectClass *klass, void *data)
3923676bc69SStefan Berger {
3933676bc69SStefan Berger     DeviceClass *dc = DEVICE_CLASS(klass);
3943676bc69SStefan Berger     SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
3953676bc69SStefan Berger     TPMIfClass *tc = TPM_IF_CLASS(klass);
3963676bc69SStefan Berger 
3973676bc69SStefan Berger     k->realize = tpm_spapr_realizefn;
3983676bc69SStefan Berger     k->reset = tpm_spapr_reset;
3993676bc69SStefan Berger     k->dt_name = "vtpm";
4003676bc69SStefan Berger     k->dt_type = "IBM,vtpm";
4013676bc69SStefan Berger     k->get_dt_compatible = tpm_spapr_get_dt_compatible;
4023676bc69SStefan Berger     k->signal_mask = 0x00000001;
4033676bc69SStefan Berger     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
4043676bc69SStefan Berger     device_class_set_props(dc, tpm_spapr_properties);
4053676bc69SStefan Berger     k->rtce_window_size = 0x10000000;
4063676bc69SStefan Berger     dc->vmsd = &vmstate_spapr_vtpm;
4073676bc69SStefan Berger 
4083676bc69SStefan Berger     tc->model = TPM_MODEL_TPM_SPAPR;
4093676bc69SStefan Berger     tc->get_version = tpm_spapr_get_version;
4103676bc69SStefan Berger     tc->request_completed = tpm_spapr_request_completed;
4113676bc69SStefan Berger }
4123676bc69SStefan Berger 
4133676bc69SStefan Berger static const TypeInfo tpm_spapr_info = {
4143676bc69SStefan Berger     .name          = TYPE_TPM_SPAPR,
4153676bc69SStefan Berger     .parent        = TYPE_VIO_SPAPR_DEVICE,
4163676bc69SStefan Berger     .instance_size = sizeof(SpaprTpmState),
4173676bc69SStefan Berger     .class_init    = tpm_spapr_class_init,
4183676bc69SStefan Berger     .interfaces = (InterfaceInfo[]) {
4193676bc69SStefan Berger         { TYPE_TPM_IF },
4203676bc69SStefan Berger         { }
4213676bc69SStefan Berger     }
4223676bc69SStefan Berger };
4233676bc69SStefan Berger 
4243676bc69SStefan Berger static void tpm_spapr_register_types(void)
4253676bc69SStefan Berger {
4263676bc69SStefan Berger     type_register_static(&tpm_spapr_info);
4273676bc69SStefan Berger }
4283676bc69SStefan Berger 
4293676bc69SStefan Berger type_init(tpm_spapr_register_types)
430