]> git.proxmox.com Git - mirror_qemu.git/blame - hw/tpm/tpm_spapr.c
Use DECLARE_*CHECKER* macros
[mirror_qemu.git] / hw / tpm / tpm_spapr.c
CommitLineData
3676bc69
SB
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"
0f7d2148 23#include "sysemu/tpm_util.h"
a3500613 24#include "tpm_prop.h"
3676bc69
SB
25
26#include "hw/ppc/spapr.h"
27#include "hw/ppc/spapr_vio.h"
28#include "trace.h"
db1015e9 29#include "qom/object.h"
3676bc69
SB
30
31#define DEBUG_SPAPR 0
32
db1015e9 33typedef struct SpaprTpmState SpaprTpmState;
8110fa1d
EH
34DECLARE_INSTANCE_CHECKER(SpaprTpmState, VIO_SPAPR_VTPM,
35 TYPE_TPM_SPAPR)
3676bc69
SB
36
37typedef 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
db1015e9 69struct SpaprTpmState {
3676bc69
SB
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
ee9a8129
SB
81 uint32_t numbytes; /* number of bytes to deliver on resume */
82
3676bc69
SB
83 TPMBackendCmd cmd;
84
85 TPMBackend *be_driver;
86 TPMVersion be_tpm_version;
87
88 size_t be_buffer_size;
db1015e9 89};
3676bc69
SB
90
91/*
92 * Send a request to the TPM.
93 */
94static 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
112static 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
128static inline int spapr_tpm_send_crq(struct SpaprVioDevice *dev, TpmCrq *crq)
129{
130 return spapr_vio_send_crq(dev, (uint8_t *)crq);
131}
132
133static 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
236static 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);
ee9a8129
SB
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
3676bc69
SB
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
279static int tpm_spapr_do_startup_tpm(SpaprTpmState *s, size_t buffersize)
280{
281 return tpm_backend_startup_tpm(s->be_driver, buffersize);
282}
283
284static 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
298static void tpm_spapr_reset(SpaprVioDevice *dev)
299{
300 SpaprTpmState *s = VIO_SPAPR_VTPM(dev);
301
302 s->state = SPAPR_VTPM_STATE_NONE;
ee9a8129 303 s->numbytes = 0;
3676bc69
SB
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);
f8b332a1
SB
311
312 if (tpm_spapr_do_startup_tpm(s, s->be_buffer_size) < 0) {
313 exit(1);
314 }
3676bc69
SB
315}
316
317static 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
ee9a8129
SB
328/* persistent state handling */
329
330static 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
342static 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
3676bc69
SB
356static const VMStateDescription vmstate_spapr_vtpm = {
357 .name = "tpm-spapr",
ee9a8129
SB
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 }
3676bc69
SB
370};
371
372static 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
378static 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
396static 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
418static 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
429static void tpm_spapr_register_types(void)
430{
431 type_register_static(&tpm_spapr_info);
432}
433
434type_init(tpm_spapr_register_types)