xref: /qemu/hw/tpm/tpm_spapr.c (revision 06b40d250ecfa1633209c2e431a7a38acfd03a98)
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