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