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