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