xref: /qemu/hw/tpm/tpm_spapr.c (revision 3676bc69b358d84a6b32d9cd44325048659a32a2)
1*3676bc69SStefan Berger /*
2*3676bc69SStefan Berger  * QEMU PowerPC pSeries Logical Partition (aka sPAPR) hardware System Emulator
3*3676bc69SStefan Berger  *
4*3676bc69SStefan Berger  * PAPR Virtual TPM
5*3676bc69SStefan Berger  *
6*3676bc69SStefan Berger  * Copyright (c) 2015, 2017, 2019 IBM Corporation.
7*3676bc69SStefan Berger  *
8*3676bc69SStefan Berger  * Authors:
9*3676bc69SStefan Berger  *    Stefan Berger <stefanb@linux.vnet.ibm.com>
10*3676bc69SStefan Berger  *
11*3676bc69SStefan Berger  * This code is licensed under the GPL version 2 or later. See the
12*3676bc69SStefan Berger  * COPYING file in the top-level directory.
13*3676bc69SStefan Berger  *
14*3676bc69SStefan Berger  */
15*3676bc69SStefan Berger 
16*3676bc69SStefan Berger #include "qemu/osdep.h"
17*3676bc69SStefan Berger #include "qemu/error-report.h"
18*3676bc69SStefan Berger #include "qapi/error.h"
19*3676bc69SStefan Berger #include "hw/qdev-properties.h"
20*3676bc69SStefan Berger #include "migration/vmstate.h"
21*3676bc69SStefan Berger 
22*3676bc69SStefan Berger #include "sysemu/tpm_backend.h"
23*3676bc69SStefan Berger #include "tpm_int.h"
24*3676bc69SStefan Berger #include "tpm_util.h"
25*3676bc69SStefan Berger 
26*3676bc69SStefan Berger #include "hw/ppc/spapr.h"
27*3676bc69SStefan Berger #include "hw/ppc/spapr_vio.h"
28*3676bc69SStefan Berger #include "trace.h"
29*3676bc69SStefan Berger 
30*3676bc69SStefan Berger #define DEBUG_SPAPR 0
31*3676bc69SStefan Berger 
32*3676bc69SStefan Berger #define VIO_SPAPR_VTPM(obj) \
33*3676bc69SStefan Berger      OBJECT_CHECK(SpaprTpmState, (obj), TYPE_TPM_SPAPR)
34*3676bc69SStefan Berger 
35*3676bc69SStefan Berger typedef struct TpmCrq {
36*3676bc69SStefan Berger     uint8_t valid;  /* 0x80: cmd; 0xc0: init crq */
37*3676bc69SStefan Berger                     /* 0x81-0x83: CRQ message response */
38*3676bc69SStefan Berger     uint8_t msg;    /* see below */
39*3676bc69SStefan Berger     uint16_t len;   /* len of TPM request; len of TPM response */
40*3676bc69SStefan Berger     uint32_t data;  /* rtce_dma_handle when sending TPM request */
41*3676bc69SStefan Berger     uint64_t reserved;
42*3676bc69SStefan Berger } TpmCrq;
43*3676bc69SStefan Berger 
44*3676bc69SStefan Berger #define SPAPR_VTPM_VALID_INIT_CRQ_COMMAND  0xC0
45*3676bc69SStefan Berger #define SPAPR_VTPM_VALID_COMMAND           0x80
46*3676bc69SStefan Berger #define SPAPR_VTPM_MSG_RESULT              0x80
47*3676bc69SStefan Berger 
48*3676bc69SStefan Berger /* msg types for valid = SPAPR_VTPM_VALID_INIT_CRQ */
49*3676bc69SStefan Berger #define SPAPR_VTPM_INIT_CRQ_RESULT           0x1
50*3676bc69SStefan Berger #define SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT  0x2
51*3676bc69SStefan Berger 
52*3676bc69SStefan Berger /* msg types for valid = SPAPR_VTPM_VALID_CMD */
53*3676bc69SStefan Berger #define SPAPR_VTPM_GET_VERSION               0x1
54*3676bc69SStefan Berger #define SPAPR_VTPM_TPM_COMMAND               0x2
55*3676bc69SStefan Berger #define SPAPR_VTPM_GET_RTCE_BUFFER_SIZE      0x3
56*3676bc69SStefan Berger #define SPAPR_VTPM_PREPARE_TO_SUSPEND        0x4
57*3676bc69SStefan Berger 
58*3676bc69SStefan Berger /* response error messages */
59*3676bc69SStefan Berger #define SPAPR_VTPM_VTPM_ERROR                0xff
60*3676bc69SStefan Berger 
61*3676bc69SStefan Berger /* error codes */
62*3676bc69SStefan Berger #define SPAPR_VTPM_ERR_COPY_IN_FAILED        0x3
63*3676bc69SStefan Berger #define SPAPR_VTPM_ERR_COPY_OUT_FAILED       0x4
64*3676bc69SStefan Berger 
65*3676bc69SStefan Berger #define TPM_SPAPR_BUFFER_MAX                 4096
66*3676bc69SStefan Berger 
67*3676bc69SStefan Berger typedef struct {
68*3676bc69SStefan Berger     SpaprVioDevice vdev;
69*3676bc69SStefan Berger 
70*3676bc69SStefan Berger     TpmCrq crq; /* track single TPM command */
71*3676bc69SStefan Berger 
72*3676bc69SStefan Berger     uint8_t state;
73*3676bc69SStefan Berger #define SPAPR_VTPM_STATE_NONE         0
74*3676bc69SStefan Berger #define SPAPR_VTPM_STATE_EXECUTION    1
75*3676bc69SStefan Berger #define SPAPR_VTPM_STATE_COMPLETION   2
76*3676bc69SStefan Berger 
77*3676bc69SStefan Berger     unsigned char *buffer;
78*3676bc69SStefan Berger 
79*3676bc69SStefan Berger     TPMBackendCmd cmd;
80*3676bc69SStefan Berger 
81*3676bc69SStefan Berger     TPMBackend *be_driver;
82*3676bc69SStefan Berger     TPMVersion be_tpm_version;
83*3676bc69SStefan Berger 
84*3676bc69SStefan Berger     size_t be_buffer_size;
85*3676bc69SStefan Berger } SpaprTpmState;
86*3676bc69SStefan Berger 
87*3676bc69SStefan Berger /*
88*3676bc69SStefan Berger  * Send a request to the TPM.
89*3676bc69SStefan Berger  */
90*3676bc69SStefan Berger static void tpm_spapr_tpm_send(SpaprTpmState *s)
91*3676bc69SStefan Berger {
92*3676bc69SStefan Berger     if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) {
93*3676bc69SStefan Berger         tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM");
94*3676bc69SStefan Berger     }
95*3676bc69SStefan Berger 
96*3676bc69SStefan Berger     s->state = SPAPR_VTPM_STATE_EXECUTION;
97*3676bc69SStefan Berger     s->cmd = (TPMBackendCmd) {
98*3676bc69SStefan Berger         .locty = 0,
99*3676bc69SStefan Berger         .in = s->buffer,
100*3676bc69SStefan Berger         .in_len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size),
101*3676bc69SStefan Berger         .out = s->buffer,
102*3676bc69SStefan Berger         .out_len = s->be_buffer_size,
103*3676bc69SStefan Berger     };
104*3676bc69SStefan Berger 
105*3676bc69SStefan Berger     tpm_backend_deliver_request(s->be_driver, &s->cmd);
106*3676bc69SStefan Berger }
107*3676bc69SStefan Berger 
108*3676bc69SStefan Berger static int tpm_spapr_process_cmd(SpaprTpmState *s, uint64_t dataptr)
109*3676bc69SStefan Berger {
110*3676bc69SStefan Berger     long rc;
111*3676bc69SStefan Berger 
112*3676bc69SStefan Berger     /* a max. of be_buffer_size bytes can be transported */
113*3676bc69SStefan Berger     rc = spapr_vio_dma_read(&s->vdev, dataptr,
114*3676bc69SStefan Berger                             s->buffer, s->be_buffer_size);
115*3676bc69SStefan Berger     if (rc) {
116*3676bc69SStefan Berger         error_report("tpm_spapr_got_payload: DMA read failure");
117*3676bc69SStefan Berger     }
118*3676bc69SStefan Berger     /* let vTPM handle any malformed request */
119*3676bc69SStefan Berger     tpm_spapr_tpm_send(s);
120*3676bc69SStefan Berger 
121*3676bc69SStefan Berger     return rc;
122*3676bc69SStefan Berger }
123*3676bc69SStefan Berger 
124*3676bc69SStefan Berger static inline int spapr_tpm_send_crq(struct SpaprVioDevice *dev, TpmCrq *crq)
125*3676bc69SStefan Berger {
126*3676bc69SStefan Berger     return spapr_vio_send_crq(dev, (uint8_t *)crq);
127*3676bc69SStefan Berger }
128*3676bc69SStefan Berger 
129*3676bc69SStefan Berger static int tpm_spapr_do_crq(struct SpaprVioDevice *dev, uint8_t *crq_data)
130*3676bc69SStefan Berger {
131*3676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
132*3676bc69SStefan Berger     TpmCrq local_crq;
133*3676bc69SStefan Berger     TpmCrq *crq = &s->crq; /* requests only */
134*3676bc69SStefan Berger     int rc;
135*3676bc69SStefan Berger     uint8_t valid = crq_data[0];
136*3676bc69SStefan Berger     uint8_t msg = crq_data[1];
137*3676bc69SStefan Berger 
138*3676bc69SStefan Berger     trace_tpm_spapr_do_crq(valid, msg);
139*3676bc69SStefan Berger 
140*3676bc69SStefan Berger     switch (valid) {
141*3676bc69SStefan Berger     case SPAPR_VTPM_VALID_INIT_CRQ_COMMAND: /* Init command/response */
142*3676bc69SStefan Berger 
143*3676bc69SStefan Berger         /* Respond to initialization request */
144*3676bc69SStefan Berger         switch (msg) {
145*3676bc69SStefan Berger         case SPAPR_VTPM_INIT_CRQ_RESULT:
146*3676bc69SStefan Berger             trace_tpm_spapr_do_crq_crq_result();
147*3676bc69SStefan Berger             memset(&local_crq, 0, sizeof(local_crq));
148*3676bc69SStefan Berger             local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND;
149*3676bc69SStefan Berger             local_crq.msg = SPAPR_VTPM_INIT_CRQ_RESULT;
150*3676bc69SStefan Berger             spapr_tpm_send_crq(dev, &local_crq);
151*3676bc69SStefan Berger             break;
152*3676bc69SStefan Berger 
153*3676bc69SStefan Berger         case SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT:
154*3676bc69SStefan Berger             trace_tpm_spapr_do_crq_crq_complete_result();
155*3676bc69SStefan Berger             memset(&local_crq, 0, sizeof(local_crq));
156*3676bc69SStefan Berger             local_crq.valid = SPAPR_VTPM_VALID_INIT_CRQ_COMMAND;
157*3676bc69SStefan Berger             local_crq.msg = SPAPR_VTPM_INIT_CRQ_COMPLETE_RESULT;
158*3676bc69SStefan Berger             spapr_tpm_send_crq(dev, &local_crq);
159*3676bc69SStefan Berger             break;
160*3676bc69SStefan Berger         }
161*3676bc69SStefan Berger 
162*3676bc69SStefan Berger         break;
163*3676bc69SStefan Berger     case SPAPR_VTPM_VALID_COMMAND: /* Payloads */
164*3676bc69SStefan Berger         switch (msg) {
165*3676bc69SStefan Berger         case SPAPR_VTPM_TPM_COMMAND:
166*3676bc69SStefan Berger             trace_tpm_spapr_do_crq_tpm_command();
167*3676bc69SStefan Berger             if (s->state == SPAPR_VTPM_STATE_EXECUTION) {
168*3676bc69SStefan Berger                 return H_BUSY;
169*3676bc69SStefan Berger             }
170*3676bc69SStefan Berger             memcpy(crq, crq_data, sizeof(*crq));
171*3676bc69SStefan Berger 
172*3676bc69SStefan Berger             rc = tpm_spapr_process_cmd(s, be32_to_cpu(crq->data));
173*3676bc69SStefan Berger 
174*3676bc69SStefan Berger             if (rc == H_SUCCESS) {
175*3676bc69SStefan Berger                 crq->valid = be16_to_cpu(0);
176*3676bc69SStefan Berger             } else {
177*3676bc69SStefan Berger                 local_crq.valid = SPAPR_VTPM_MSG_RESULT;
178*3676bc69SStefan Berger                 local_crq.msg = SPAPR_VTPM_VTPM_ERROR;
179*3676bc69SStefan Berger                 local_crq.len = cpu_to_be16(0);
180*3676bc69SStefan Berger                 local_crq.data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_IN_FAILED);
181*3676bc69SStefan Berger                 spapr_tpm_send_crq(dev, &local_crq);
182*3676bc69SStefan Berger             }
183*3676bc69SStefan Berger             break;
184*3676bc69SStefan Berger 
185*3676bc69SStefan Berger         case SPAPR_VTPM_GET_RTCE_BUFFER_SIZE:
186*3676bc69SStefan Berger             trace_tpm_spapr_do_crq_tpm_get_rtce_buffer_size(s->be_buffer_size);
187*3676bc69SStefan Berger             local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
188*3676bc69SStefan Berger             local_crq.msg = SPAPR_VTPM_GET_RTCE_BUFFER_SIZE |
189*3676bc69SStefan Berger                             SPAPR_VTPM_MSG_RESULT;
190*3676bc69SStefan Berger             local_crq.len = cpu_to_be16(s->be_buffer_size);
191*3676bc69SStefan Berger             spapr_tpm_send_crq(dev, &local_crq);
192*3676bc69SStefan Berger             break;
193*3676bc69SStefan Berger 
194*3676bc69SStefan Berger         case SPAPR_VTPM_GET_VERSION:
195*3676bc69SStefan Berger             local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
196*3676bc69SStefan Berger             local_crq.msg = SPAPR_VTPM_GET_VERSION | SPAPR_VTPM_MSG_RESULT;
197*3676bc69SStefan Berger             local_crq.len = cpu_to_be16(0);
198*3676bc69SStefan Berger             switch (s->be_tpm_version) {
199*3676bc69SStefan Berger             case TPM_VERSION_1_2:
200*3676bc69SStefan Berger                 local_crq.data = cpu_to_be32(1);
201*3676bc69SStefan Berger                 break;
202*3676bc69SStefan Berger             case TPM_VERSION_2_0:
203*3676bc69SStefan Berger                 local_crq.data = cpu_to_be32(2);
204*3676bc69SStefan Berger                 break;
205*3676bc69SStefan Berger             default:
206*3676bc69SStefan Berger                 g_assert_not_reached();
207*3676bc69SStefan Berger                 break;
208*3676bc69SStefan Berger             }
209*3676bc69SStefan Berger             trace_tpm_spapr_do_crq_get_version(be32_to_cpu(local_crq.data));
210*3676bc69SStefan Berger             spapr_tpm_send_crq(dev, &local_crq);
211*3676bc69SStefan Berger             break;
212*3676bc69SStefan Berger 
213*3676bc69SStefan Berger         case SPAPR_VTPM_PREPARE_TO_SUSPEND:
214*3676bc69SStefan Berger             trace_tpm_spapr_do_crq_prepare_to_suspend();
215*3676bc69SStefan Berger             local_crq.valid = SPAPR_VTPM_VALID_COMMAND;
216*3676bc69SStefan Berger             local_crq.msg = SPAPR_VTPM_PREPARE_TO_SUSPEND |
217*3676bc69SStefan Berger                             SPAPR_VTPM_MSG_RESULT;
218*3676bc69SStefan Berger             spapr_tpm_send_crq(dev, &local_crq);
219*3676bc69SStefan Berger             break;
220*3676bc69SStefan Berger 
221*3676bc69SStefan Berger         default:
222*3676bc69SStefan Berger             trace_tpm_spapr_do_crq_unknown_msg_type(crq->msg);
223*3676bc69SStefan Berger         }
224*3676bc69SStefan Berger         break;
225*3676bc69SStefan Berger     default:
226*3676bc69SStefan Berger         trace_tpm_spapr_do_crq_unknown_crq(valid, msg);
227*3676bc69SStefan Berger     };
228*3676bc69SStefan Berger 
229*3676bc69SStefan Berger     return H_SUCCESS;
230*3676bc69SStefan Berger }
231*3676bc69SStefan Berger 
232*3676bc69SStefan Berger static void tpm_spapr_request_completed(TPMIf *ti, int ret)
233*3676bc69SStefan Berger {
234*3676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(ti);
235*3676bc69SStefan Berger     TpmCrq *crq = &s->crq;
236*3676bc69SStefan Berger     uint32_t len;
237*3676bc69SStefan Berger     int rc;
238*3676bc69SStefan Berger 
239*3676bc69SStefan Berger     s->state = SPAPR_VTPM_STATE_COMPLETION;
240*3676bc69SStefan Berger 
241*3676bc69SStefan Berger     /* a max. of be_buffer_size bytes can be transported */
242*3676bc69SStefan Berger     len = MIN(tpm_cmd_get_size(s->buffer), s->be_buffer_size);
243*3676bc69SStefan Berger     rc = spapr_vio_dma_write(&s->vdev, be32_to_cpu(crq->data),
244*3676bc69SStefan Berger                              s->buffer, len);
245*3676bc69SStefan Berger 
246*3676bc69SStefan Berger     if (trace_event_get_state_backends(TRACE_TPM_SPAPR_SHOW_BUFFER)) {
247*3676bc69SStefan Berger         tpm_util_show_buffer(s->buffer, len, "From TPM");
248*3676bc69SStefan Berger     }
249*3676bc69SStefan Berger 
250*3676bc69SStefan Berger     crq->valid = SPAPR_VTPM_MSG_RESULT;
251*3676bc69SStefan Berger     if (rc == H_SUCCESS) {
252*3676bc69SStefan Berger         crq->msg = SPAPR_VTPM_TPM_COMMAND | SPAPR_VTPM_MSG_RESULT;
253*3676bc69SStefan Berger         crq->len = cpu_to_be16(len);
254*3676bc69SStefan Berger     } else {
255*3676bc69SStefan Berger         error_report("%s: DMA write failure", __func__);
256*3676bc69SStefan Berger         crq->msg = SPAPR_VTPM_VTPM_ERROR;
257*3676bc69SStefan Berger         crq->len = cpu_to_be16(0);
258*3676bc69SStefan Berger         crq->data = cpu_to_be32(SPAPR_VTPM_ERR_COPY_OUT_FAILED);
259*3676bc69SStefan Berger     }
260*3676bc69SStefan Berger 
261*3676bc69SStefan Berger     rc = spapr_tpm_send_crq(&s->vdev, crq);
262*3676bc69SStefan Berger     if (rc) {
263*3676bc69SStefan Berger         error_report("%s: Error sending response", __func__);
264*3676bc69SStefan Berger     }
265*3676bc69SStefan Berger }
266*3676bc69SStefan Berger 
267*3676bc69SStefan Berger static int tpm_spapr_do_startup_tpm(SpaprTpmState *s, size_t buffersize)
268*3676bc69SStefan Berger {
269*3676bc69SStefan Berger     return tpm_backend_startup_tpm(s->be_driver, buffersize);
270*3676bc69SStefan Berger }
271*3676bc69SStefan Berger 
272*3676bc69SStefan Berger static const char *tpm_spapr_get_dt_compatible(SpaprVioDevice *dev)
273*3676bc69SStefan Berger {
274*3676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
275*3676bc69SStefan Berger 
276*3676bc69SStefan Berger     switch (s->be_tpm_version) {
277*3676bc69SStefan Berger     case TPM_VERSION_1_2:
278*3676bc69SStefan Berger         return "IBM,vtpm";
279*3676bc69SStefan Berger     case TPM_VERSION_2_0:
280*3676bc69SStefan Berger         return "IBM,vtpm20";
281*3676bc69SStefan Berger     default:
282*3676bc69SStefan Berger         g_assert_not_reached();
283*3676bc69SStefan Berger     }
284*3676bc69SStefan Berger }
285*3676bc69SStefan Berger 
286*3676bc69SStefan Berger static void tpm_spapr_reset(SpaprVioDevice *dev)
287*3676bc69SStefan Berger {
288*3676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
289*3676bc69SStefan Berger 
290*3676bc69SStefan Berger     s->state = SPAPR_VTPM_STATE_NONE;
291*3676bc69SStefan Berger 
292*3676bc69SStefan Berger     s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
293*3676bc69SStefan Berger 
294*3676bc69SStefan Berger     s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
295*3676bc69SStefan Berger                             TPM_SPAPR_BUFFER_MAX);
296*3676bc69SStefan Berger 
297*3676bc69SStefan Berger     tpm_backend_reset(s->be_driver);
298*3676bc69SStefan Berger     tpm_spapr_do_startup_tpm(s, s->be_buffer_size);
299*3676bc69SStefan Berger }
300*3676bc69SStefan Berger 
301*3676bc69SStefan Berger static enum TPMVersion tpm_spapr_get_version(TPMIf *ti)
302*3676bc69SStefan Berger {
303*3676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(ti);
304*3676bc69SStefan Berger 
305*3676bc69SStefan Berger     if (tpm_backend_had_startup_error(s->be_driver)) {
306*3676bc69SStefan Berger         return TPM_VERSION_UNSPEC;
307*3676bc69SStefan Berger     }
308*3676bc69SStefan Berger 
309*3676bc69SStefan Berger     return tpm_backend_get_tpm_version(s->be_driver);
310*3676bc69SStefan Berger }
311*3676bc69SStefan Berger 
312*3676bc69SStefan Berger static const VMStateDescription vmstate_spapr_vtpm = {
313*3676bc69SStefan Berger     .name = "tpm-spapr",
314*3676bc69SStefan Berger     .unmigratable = 1,
315*3676bc69SStefan Berger };
316*3676bc69SStefan Berger 
317*3676bc69SStefan Berger static Property tpm_spapr_properties[] = {
318*3676bc69SStefan Berger     DEFINE_SPAPR_PROPERTIES(SpaprTpmState, vdev),
319*3676bc69SStefan Berger     DEFINE_PROP_TPMBE("tpmdev", SpaprTpmState, be_driver),
320*3676bc69SStefan Berger     DEFINE_PROP_END_OF_LIST(),
321*3676bc69SStefan Berger };
322*3676bc69SStefan Berger 
323*3676bc69SStefan Berger static void tpm_spapr_realizefn(SpaprVioDevice *dev, Error **errp)
324*3676bc69SStefan Berger {
325*3676bc69SStefan Berger     SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
326*3676bc69SStefan Berger 
327*3676bc69SStefan Berger     if (!tpm_find()) {
328*3676bc69SStefan Berger         error_setg(errp, "at most one TPM device is permitted");
329*3676bc69SStefan Berger         return;
330*3676bc69SStefan Berger     }
331*3676bc69SStefan Berger 
332*3676bc69SStefan Berger     dev->crq.SendFunc = tpm_spapr_do_crq;
333*3676bc69SStefan Berger 
334*3676bc69SStefan Berger     if (!s->be_driver) {
335*3676bc69SStefan Berger         error_setg(errp, "'tpmdev' property is required");
336*3676bc69SStefan Berger         return;
337*3676bc69SStefan Berger     }
338*3676bc69SStefan Berger     s->buffer = g_malloc(TPM_SPAPR_BUFFER_MAX);
339*3676bc69SStefan Berger }
340*3676bc69SStefan Berger 
341*3676bc69SStefan Berger static void tpm_spapr_class_init(ObjectClass *klass, void *data)
342*3676bc69SStefan Berger {
343*3676bc69SStefan Berger     DeviceClass *dc = DEVICE_CLASS(klass);
344*3676bc69SStefan Berger     SpaprVioDeviceClass *k = VIO_SPAPR_DEVICE_CLASS(klass);
345*3676bc69SStefan Berger     TPMIfClass *tc = TPM_IF_CLASS(klass);
346*3676bc69SStefan Berger 
347*3676bc69SStefan Berger     k->realize = tpm_spapr_realizefn;
348*3676bc69SStefan Berger     k->reset = tpm_spapr_reset;
349*3676bc69SStefan Berger     k->dt_name = "vtpm";
350*3676bc69SStefan Berger     k->dt_type = "IBM,vtpm";
351*3676bc69SStefan Berger     k->get_dt_compatible = tpm_spapr_get_dt_compatible;
352*3676bc69SStefan Berger     k->signal_mask = 0x00000001;
353*3676bc69SStefan Berger     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
354*3676bc69SStefan Berger     device_class_set_props(dc, tpm_spapr_properties);
355*3676bc69SStefan Berger     k->rtce_window_size = 0x10000000;
356*3676bc69SStefan Berger     dc->vmsd = &vmstate_spapr_vtpm;
357*3676bc69SStefan Berger 
358*3676bc69SStefan Berger     tc->model = TPM_MODEL_TPM_SPAPR;
359*3676bc69SStefan Berger     tc->get_version = tpm_spapr_get_version;
360*3676bc69SStefan Berger     tc->request_completed = tpm_spapr_request_completed;
361*3676bc69SStefan Berger }
362*3676bc69SStefan Berger 
363*3676bc69SStefan Berger static const TypeInfo tpm_spapr_info = {
364*3676bc69SStefan Berger     .name          = TYPE_TPM_SPAPR,
365*3676bc69SStefan Berger     .parent        = TYPE_VIO_SPAPR_DEVICE,
366*3676bc69SStefan Berger     .instance_size = sizeof(SpaprTpmState),
367*3676bc69SStefan Berger     .class_init    = tpm_spapr_class_init,
368*3676bc69SStefan Berger     .interfaces = (InterfaceInfo[]) {
369*3676bc69SStefan Berger         { TYPE_TPM_IF },
370*3676bc69SStefan Berger         { }
371*3676bc69SStefan Berger     }
372*3676bc69SStefan Berger };
373*3676bc69SStefan Berger 
374*3676bc69SStefan Berger static void tpm_spapr_register_types(void)
375*3676bc69SStefan Berger {
376*3676bc69SStefan Berger     type_register_static(&tpm_spapr_info);
377*3676bc69SStefan Berger }
378*3676bc69SStefan Berger 
379*3676bc69SStefan Berger type_init(tpm_spapr_register_types)
380