xref: /qemu/hw/tpm/tpm_spapr.c (revision f8b332a1ff107dc014a52eaf9bf547995205f18a)
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"
230f7d2148SPhilippe Mathieu-Daudé #include "sysemu/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"
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 
79ee9a8129SStefan Berger     uint32_t numbytes; /* number of bytes to deliver on resume */
80ee9a8129SStefan 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);
245ee9a8129SStefan Berger 
246ee9a8129SStefan Berger     if (runstate_check(RUN_STATE_FINISH_MIGRATE)) {
247ee9a8129SStefan Berger         trace_tpm_spapr_caught_response(len);
248ee9a8129SStefan Berger         /* defer delivery of response until .post_load */
249ee9a8129SStefan Berger         s->numbytes = len;
250ee9a8129SStefan Berger         return;
251ee9a8129SStefan Berger     }
252ee9a8129SStefan 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;
301ee9a8129SStefan 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);
309*f8b332a1SStefan Berger 
310*f8b332a1SStefan Berger     if (tpm_spapr_do_startup_tpm(s, s->be_buffer_size) < 0) {
311*f8b332a1SStefan Berger         exit(1);
312*f8b332a1SStefan Berger     }
3133676bc69SStefan Berger }
3143676bc69SStefan Berger 
3153676bc69SStefan Berger static enum TPMVersion tpm_spapr_get_version(TPMIf *ti)
3163676bc69SStefan Berger {
3173676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(ti);
3183676bc69SStefan Berger 
3193676bc69SStefan Berger     if (tpm_backend_had_startup_error(s->be_driver)) {
3203676bc69SStefan Berger         return TPM_VERSION_UNSPEC;
3213676bc69SStefan Berger     }
3223676bc69SStefan Berger 
3233676bc69SStefan Berger     return tpm_backend_get_tpm_version(s->be_driver);
3243676bc69SStefan Berger }
3253676bc69SStefan Berger 
326ee9a8129SStefan Berger /* persistent state handling */
327ee9a8129SStefan Berger 
328ee9a8129SStefan Berger static int tpm_spapr_pre_save(void *opaque)
329ee9a8129SStefan Berger {
330ee9a8129SStefan Berger     SpaprTpmState *s = opaque;
331ee9a8129SStefan Berger 
332ee9a8129SStefan Berger     tpm_backend_finish_sync(s->be_driver);
333ee9a8129SStefan Berger     /*
334ee9a8129SStefan Berger      * we cannot deliver the results to the VM since DMA would touch VM memory
335ee9a8129SStefan Berger      */
336ee9a8129SStefan Berger 
337ee9a8129SStefan Berger     return 0;
338ee9a8129SStefan Berger }
339ee9a8129SStefan Berger 
340ee9a8129SStefan Berger static int tpm_spapr_post_load(void *opaque, int version_id)
341ee9a8129SStefan Berger {
342ee9a8129SStefan Berger     SpaprTpmState *s = opaque;
343ee9a8129SStefan Berger 
344ee9a8129SStefan Berger     if (s->numbytes) {
345ee9a8129SStefan Berger         trace_tpm_spapr_post_load();
346ee9a8129SStefan Berger         /* deliver the results to the VM via DMA */
347ee9a8129SStefan Berger         tpm_spapr_request_completed(TPM_IF(s), 0);
348ee9a8129SStefan Berger         s->numbytes = 0;
349ee9a8129SStefan Berger     }
350ee9a8129SStefan Berger 
351ee9a8129SStefan Berger     return 0;
352ee9a8129SStefan Berger }
353ee9a8129SStefan Berger 
3543676bc69SStefan Berger static const VMStateDescription vmstate_spapr_vtpm = {
3553676bc69SStefan Berger     .name = "tpm-spapr",
356ee9a8129SStefan Berger     .pre_save = tpm_spapr_pre_save,
357ee9a8129SStefan Berger     .post_load = tpm_spapr_post_load,
358ee9a8129SStefan Berger     .fields = (VMStateField[]) {
359ee9a8129SStefan Berger         VMSTATE_SPAPR_VIO(vdev, SpaprTpmState),
360ee9a8129SStefan Berger 
361ee9a8129SStefan Berger         VMSTATE_UINT8(state, SpaprTpmState),
362ee9a8129SStefan Berger         VMSTATE_UINT32(numbytes, SpaprTpmState),
363ee9a8129SStefan Berger         VMSTATE_VBUFFER_UINT32(buffer, SpaprTpmState, 0, NULL, numbytes),
364ee9a8129SStefan Berger         /* remember DMA address */
365ee9a8129SStefan Berger         VMSTATE_UINT32(crq.data, SpaprTpmState),
366ee9a8129SStefan Berger         VMSTATE_END_OF_LIST(),
367ee9a8129SStefan Berger     }
3683676bc69SStefan Berger };
3693676bc69SStefan Berger 
3703676bc69SStefan Berger static Property tpm_spapr_properties[] = {
3713676bc69SStefan Berger     DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev),
3723676bc69SStefan Berger     DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver),
3733676bc69SStefan Berger     DEFINE_PROP_END_OF_LIST(),
3743676bc69SStefan Berger };
3753676bc69SStefan Berger 
3763676bc69SStefan Berger static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp)
3773676bc69SStefan Berger {
3783676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
3793676bc69SStefan Berger 
3803676bc69SStefan Berger     if (!tpm_find()) {
3813676bc69SStefan Berger         error_setg(errp, "at most one TPM device is permitted");
3823676bc69SStefan Berger         return;
3833676bc69SStefan Berger     }
3843676bc69SStefan Berger 
3853676bc69SStefan Berger     dev->crq.SendFunc = tpm_spapr_do_crq;
3863676bc69SStefan Berger 
3873676bc69SStefan Berger     if (!s->be_driver) {
3883676bc69SStefan Berger         error_setg(errp, "'tpmdev' property is required");
3893676bc69SStefan Berger         return;
3903676bc69SStefan Berger     }
3913676bc69SStefan Berger     s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX);
3923676bc69SStefan Berger }
3933676bc69SStefan Berger 
3943676bc69SStefan Berger static void tpm_spapr_class_init(ObjectClass *klass, void *data)
3953676bc69SStefan Berger {
3963676bc69SStefan Berger     DeviceClass *dc = DEVICE_CLASS(klass);
3973676bc69SStefan Berger     SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
3983676bc69SStefan Berger     TPMIfClass *tc = TPM_IF_CLASS(klass);
3993676bc69SStefan Berger 
4003676bc69SStefan Berger     k->realize = tpm_spapr_realizefn;
4013676bc69SStefan Berger     k->reset = tpm_spapr_reset;
4023676bc69SStefan Berger     k->dt_name = "vtpm";
4033676bc69SStefan Berger     k->dt_type = "IBM,vtpm";
4043676bc69SStefan Berger     k->get_dt_compatible = tpm_spapr_get_dt_compatible;
4053676bc69SStefan Berger     k->signal_mask = 0x00000001;
4063676bc69SStefan Berger     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
4073676bc69SStefan Berger     device_class_set_props(dc, tpm_spapr_properties);
4083676bc69SStefan Berger     k->rtce_window_size = 0x10000000;
4093676bc69SStefan Berger     dc->vmsd = &vmstate_spapr_vtpm;
4103676bc69SStefan Berger 
4113676bc69SStefan Berger     tc->model = TPM_MODEL_TPM_SPAPR;
4123676bc69SStefan Berger     tc->get_version = tpm_spapr_get_version;
4133676bc69SStefan Berger     tc->request_completed = tpm_spapr_request_completed;
4143676bc69SStefan Berger }
4153676bc69SStefan Berger 
4163676bc69SStefan Berger static const TypeInfo tpm_spapr_info = {
4173676bc69SStefan Berger     .name          = TYPE_TPM_SPAPR,
4183676bc69SStefan Berger     .parent        = TYPE_VIO_SPAPR_DEVICE,
4193676bc69SStefan Berger     .instance_size = sizeof(SpaprTpmState),
4203676bc69SStefan Berger     .class_init    = tpm_spapr_class_init,
4213676bc69SStefan Berger     .interfaces = (InterfaceInfo[]) {
4223676bc69SStefan Berger         { TYPE_TPM_IF },
4233676bc69SStefan Berger         { }
4243676bc69SStefan Berger     }
4253676bc69SStefan Berger };
4263676bc69SStefan Berger 
4273676bc69SStefan Berger static void tpm_spapr_register_types(void)
4283676bc69SStefan Berger {
4293676bc69SStefan Berger     type_register_static(&tpm_spapr_info);
4303676bc69SStefan Berger }
4313676bc69SStefan Berger 
4323676bc69SStefan Berger type_init(tpm_spapr_register_types)
433