master
c 561 lines 17.3 KB
Raw
1 /*
2 * tpm_crb.c - QEMU's TPM CRB interface emulator
3 *
4 * Copyright (c) 2018 Red Hat, Inc.
5 *
6 * Authors:
7 * Marc-André Lureau <marcandre.lureau@redhat.com>
8 *
9 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 * See the COPYING file in the top-level directory.
11 *
12 * tpm_crb is a device for TPM 2.0 Command Response Buffer (CRB) Interface
13 * as defined in TCG PC Client Platform TPM Profile (PTP) Specification
14 * Family “2.0” Level 00 Revision 01.03 v22
15 */
16
17 #include "qemu/osdep.h"
18
19 #include "qemu/module.h"
20 #include "qemu/error-report.h"
21 #include "qapi/error.h"
22 #include "system/address-spaces.h"
23 #include "hw/core/qdev-properties.h"
24 #include "hw/pci/pci_ids.h"
25 #include "hw/acpi/tpm.h"
26 #include "migration/vmstate.h"
27 #include "migration/blocker.h"
28 #include "system/tpm_backend.h"
29 #include "system/tpm_util.h"
30 #include "system/reset.h"
31 #include "system/xen.h"
32 #include "tpm_prop.h"
33 #include "tpm_ppi.h"
34 #include "trace.h"
35 #include "qom/object.h"
36
37 struct CRBState {
38 DeviceState parent_obj;
39
40 TPMBackend *tpmbe;
41 TPMBackendCmd cmd;
42 uint32_t regs[TPM_CRB_R_MAX];
43 size_t be_buffer_size;
44 MemoryRegion mmio;
45 MemoryRegion cmdmem;
46
47 GByteArray *command_buffer;
48 GByteArray *response_buffer;
49 uint32_t response_offset;
50
51 TPMPPI ppi;
52
53 bool cap_chunk;
54 bool allow_chunk_migration;
55 Error *migration_blocker;
56 };
57 typedef struct CRBState CRBState;
58
59 DECLARE_INSTANCE_CHECKER(CRBState, CRB,
60 TYPE_TPM_CRB)
61
62 #define CRB_INTF_TYPE_CRB_ACTIVE 0b1
63 #define CRB_INTF_VERSION_CRB 0b1
64 #define CRB_INTF_CAP_LOCALITY_0_ONLY 0b0
65 #define CRB_INTF_CAP_IDLE_FAST 0b0
66 #define CRB_INTF_CAP_XFER_SIZE_64 0b11
67 #define CRB_INTF_CAP_FIFO_NOT_SUPPORTED 0b0
68 #define CRB_INTF_CAP_CRB_SUPPORTED 0b1
69 #define CRB_INTF_IF_SELECTOR_CRB 0b1
70 #define CRB_INTF_CAP_CRB_CHUNK 0b1
71
72 #define CRB_CTRL_CMD_SIZE (TPM_CRB_ADDR_SIZE - A_CRB_DATA_BUFFER)
73 #define TPM_HEADER_SIZE 10
74
75 enum crb_loc_ctrl {
76 CRB_LOC_CTRL_REQUEST_ACCESS = BIT(0),
77 CRB_LOC_CTRL_RELINQUISH = BIT(1),
78 CRB_LOC_CTRL_SEIZE = BIT(2),
79 CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT = BIT(3),
80 };
81
82 enum crb_ctrl_req {
83 CRB_CTRL_REQ_CMD_READY = BIT(0),
84 CRB_CTRL_REQ_GO_IDLE = BIT(1),
85 };
86
87 enum crb_start {
88 CRB_START_INVOKE = BIT(0),
89 CRB_START_RSP_RETRY = BIT(1),
90 CRB_START_NEXT_CHUNK = BIT(2),
91 };
92
93 enum crb_cancel {
94 CRB_CANCEL_INVOKE = BIT(0),
95 };
96
97 #define TPM_CRB_NO_LOCALITY 0xff
98
99 static void tpm_crb_clear_internal_buffers(CRBState *s)
100 {
101 g_byte_array_set_size(s->response_buffer, 0);
102 g_byte_array_set_size(s->command_buffer, 0);
103 s->response_offset = 0;
104 }
105
106 static uint64_t tpm_crb_mmio_read(void *opaque, hwaddr addr,
107 unsigned size)
108 {
109 CRBState *s = CRB(opaque);
110 void *regs = (void *)&s->regs + (addr & ~3);
111 unsigned offset = addr & 3;
112 uint32_t val = *(uint32_t *)regs >> (8 * offset);
113
114 switch (addr) {
115 case A_CRB_LOC_STATE:
116 val |= !tpm_backend_get_tpm_established_flag(s->tpmbe);
117 break;
118 }
119
120 trace_tpm_crb_mmio_read(addr, size, val);
121
122 return val;
123 }
124
125 static uint8_t tpm_crb_get_active_locty(CRBState *s)
126 {
127 if (!ARRAY_FIELD_EX32(s->regs, CRB_LOC_STATE, locAssigned)) {
128 return TPM_CRB_NO_LOCALITY;
129 }
130 return ARRAY_FIELD_EX32(s->regs, CRB_LOC_STATE, activeLocality);
131 }
132
133 static bool tpm_crb_append_command_request(CRBState *s)
134 {
135 /*
136 * The linux guest writes the TPM command to the MMIO region in chunks.
137 * This function appends a chunk from the MMIO region to internal
138 * command_buffer.
139 */
140 void *mem = memory_region_get_ram_ptr(&s->cmdmem);
141 uint32_t to_copy = 0;
142 uint32_t total_request_size = 0;
143
144 /*
145 * The initial call extracts the total TPM command size
146 * from its header. For the subsequent calls, the data already
147 * appended in the command_buffer is used to calculate the total
148 * size, as its header stays the same.
149 */
150 if (s->command_buffer->len == 0) {
151 total_request_size = tpm_cmd_get_size(mem);
152 if (total_request_size < TPM_HEADER_SIZE) {
153 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS, tpmSts, 1);
154 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 0);
155 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
156 tpm_crb_clear_internal_buffers(s);
157 error_report("Command size %" PRIu32 " less than "
158 "TPM header size %" PRIu32,
159 total_request_size, (uint32_t)TPM_HEADER_SIZE);
160 return false;
161 }
162 } else {
163 total_request_size = tpm_cmd_get_size(s->command_buffer->data);
164 }
165 total_request_size = MIN(total_request_size, s->be_buffer_size);
166
167 if (total_request_size > s->command_buffer->len) {
168 uint32_t remaining = total_request_size - s->command_buffer->len;
169 to_copy = MIN(remaining, CRB_CTRL_CMD_SIZE);
170 g_byte_array_append(s->command_buffer, (guint8 *)mem, to_copy);
171 }
172 return true;
173 }
174
175 static void tpm_crb_fill_command_response(CRBState *s)
176 {
177 /*
178 * Response from the tpm backend will be stored in the internal
179 * response_buffer. This function will serve that accumulated response
180 * to the linux guest in chunks by writing it back to MMIO region.
181 */
182 void *mem = memory_region_get_ram_ptr(&s->cmdmem);
183 uint32_t remaining = s->response_buffer->len - s->response_offset;
184 uint32_t to_copy = MIN(CRB_CTRL_CMD_SIZE, remaining);
185
186 memcpy(mem, s->response_buffer->data + s->response_offset, to_copy);
187
188 if (to_copy < CRB_CTRL_CMD_SIZE) {
189 memset((guint8 *)mem + to_copy, 0, CRB_CTRL_CMD_SIZE - to_copy);
190 }
191
192 s->response_offset += to_copy;
193 memory_region_set_dirty(&s->cmdmem, 0, CRB_CTRL_CMD_SIZE);
194 }
195
196 static void tpm_crb_mmio_write(void *opaque, hwaddr addr,
197 uint64_t val, unsigned size)
198 {
199 CRBState *s = CRB(opaque);
200 uint8_t locty = addr >> 12;
201
202 trace_tpm_crb_mmio_write(addr, size, val);
203
204 switch (addr) {
205 case A_CRB_CTRL_REQ:
206 switch (val) {
207 case CRB_CTRL_REQ_CMD_READY:
208 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
209 tpmIdle, 0);
210 break;
211 case CRB_CTRL_REQ_GO_IDLE:
212 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
213 tpmIdle, 1);
214 break;
215 }
216 break;
217 case A_CRB_CTRL_CANCEL:
218 if (val == CRB_CANCEL_INVOKE) {
219 if (s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) {
220 tpm_backend_cancel_cmd(s->tpmbe);
221 }
222 tpm_crb_clear_internal_buffers(s);
223 }
224 break;
225 case A_CRB_CTRL_START:
226 if (tpm_crb_get_active_locty(s) != locty) {
227 break;
228 }
229 if (s->regs[R_CRB_CTRL_START] & CRB_START_INVOKE) {
230 /*
231 * Backend TPM is busy processing a request.
232 */
233 break;
234 }
235 if (val & CRB_START_INVOKE) {
236 if (!tpm_crb_append_command_request(s)) {
237 break;
238 }
239 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 1);
240 g_byte_array_set_size(s->response_buffer, s->be_buffer_size);
241 s->cmd = (TPMBackendCmd) {
242 .in = s->command_buffer->data,
243 .in_len = s->command_buffer->len,
244 .out = s->response_buffer->data,
245 .out_len = s->response_buffer->len,
246 };
247 tpm_backend_deliver_request(s->tpmbe, &s->cmd);
248 } else if (val & CRB_START_NEXT_CHUNK) {
249 if (!s->cap_chunk) {
250 break;
251 }
252 /*
253 * nextChunk is used both while sending and receiving data.
254 * To distinguish between the two, response_buffer is checked.
255 * If it does not have data, then that means we have not yet
256 * sent the command to the tpm backend, and therefore call
257 * tpm_crb_append_command_request().
258 */
259 if (s->response_buffer->len > 0 &&
260 s->response_offset < s->response_buffer->len) {
261 tpm_crb_fill_command_response(s);
262 } else {
263 if (!tpm_crb_append_command_request(s)) {
264 break;
265 }
266 }
267 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
268 } else if (val & CRB_START_RSP_RETRY) {
269 if (!s->cap_chunk) {
270 break;
271 }
272 if (s->response_buffer->len > 0) {
273 s->response_offset = 0;
274 tpm_crb_fill_command_response(s);
275 }
276 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, crbRspRetry, 0);
277 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
278 }
279 break;
280 case A_CRB_LOC_CTRL:
281 switch (val) {
282 case CRB_LOC_CTRL_RESET_ESTABLISHMENT_BIT:
283 /* not loc 3 or 4 */
284 break;
285 case CRB_LOC_CTRL_RELINQUISH:
286 ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE,
287 locAssigned, 0);
288 ARRAY_FIELD_DP32(s->regs, CRB_LOC_STS,
289 Granted, 0);
290 break;
291 case CRB_LOC_CTRL_REQUEST_ACCESS:
292 ARRAY_FIELD_DP32(s->regs, CRB_LOC_STS,
293 Granted, 1);
294 ARRAY_FIELD_DP32(s->regs, CRB_LOC_STS,
295 beenSeized, 0);
296 ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE,
297 locAssigned, 1);
298 break;
299 }
300 break;
301 }
302 }
303
304 static const MemoryRegionOps tpm_crb_memory_ops = {
305 .read = tpm_crb_mmio_read,
306 .write = tpm_crb_mmio_write,
307 .endianness = DEVICE_LITTLE_ENDIAN,
308 .valid = {
309 .min_access_size = 1,
310 .max_access_size = 4,
311 },
312 };
313
314 static void tpm_crb_request_completed(TPMIf *ti, int ret)
315 {
316 CRBState *s = CRB(ti);
317
318 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, Start, 0);
319 if (ret != 0) {
320 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
321 tpmSts, 1); /* fatal error */
322 tpm_crb_clear_internal_buffers(s);
323 } else {
324 uint32_t actual_resp_size = tpm_cmd_get_size(s->response_buffer->data);
325 uint32_t total_resp_size = MIN(actual_resp_size, s->be_buffer_size);
326 g_byte_array_set_size(s->response_buffer, total_resp_size);
327 s->response_offset = 0;
328 }
329 /*
330 * Send the first chunk. Subsequent chunks will be sent
331 * on receiving nextChunk from the guest
332 */
333 tpm_crb_fill_command_response(s);
334 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, nextChunk, 0);
335 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_START, crbRspRetry, 0);
336 g_byte_array_set_size(s->command_buffer, 0);
337 }
338
339 static enum TPMVersion tpm_crb_get_version(TPMIf *ti)
340 {
341 CRBState *s = CRB(ti);
342
343 return tpm_backend_get_tpm_version(s->tpmbe);
344 }
345
346 static int tpm_crb_pre_save(void *opaque)
347 {
348 CRBState *s = opaque;
349
350 tpm_backend_finish_sync(s->tpmbe);
351
352 return 0;
353 }
354
355 static bool tpm_crb_chunk_needed(void *opaque)
356 {
357 CRBState *s = opaque;
358
359 if (!s->allow_chunk_migration) {
360 return false;
361 }
362
363 return ((s->command_buffer && s->command_buffer->len > 0) ||
364 (s->response_buffer && s->response_buffer->len > 0));
365 }
366
367 static bool tpm_crb_chunk_post_load(void *opaque, int version_id, Error **errp)
368 {
369 CRBState *s = opaque;
370
371 /*
372 * The external TPM emulator (example swtpm) determines the backend
373 * buffer capacity (s->be_buffer_size). This check ensures that if we
374 * migrate from a source with a PQC-enabled emulator that supports
375 * larger buffers to a destination with a non-PQC emulator, the
376 * migrated data does not exceed the destination's capacity.
377 */
378 if (s->response_buffer->len > s->be_buffer_size ||
379 s->command_buffer->len > s->be_buffer_size) {
380 error_setg(errp, "tpm-crb: Buffer sizes exceed backend capacity");
381 return false;
382 }
383 return true;
384 }
385
386 static const VMStateDescription vmstate_tpm_crb_chunk = {
387 .name = "tpm-crb/chunk",
388 .version_id = 0,
389 .needed = tpm_crb_chunk_needed,
390 .post_load_errp = tpm_crb_chunk_post_load,
391 .fields = (const VMStateField[]) {
392 VMSTATE_GBYTEARRAY(command_buffer, CRBState, 0),
393 VMSTATE_GBYTEARRAY(response_buffer, CRBState, 0),
394 VMSTATE_UINT32(response_offset, CRBState),
395 VMSTATE_END_OF_LIST()
396 }
397 };
398
399 static const VMStateDescription vmstate_tpm_crb = {
400 .name = "tpm-crb",
401 .pre_save = tpm_crb_pre_save,
402 .fields = (const VMStateField[]) {
403 VMSTATE_UINT32_ARRAY(regs, CRBState, TPM_CRB_R_MAX),
404 VMSTATE_END_OF_LIST(),
405 },
406 .subsections = (const VMStateDescription * const []) {
407 &vmstate_tpm_crb_chunk,
408 NULL,
409 }
410 };
411
412 static const Property tpm_crb_properties[] = {
413 DEFINE_PROP_TPMBE("tpmdev", CRBState, tpmbe),
414 DEFINE_PROP_BOOL("cap-chunk", CRBState, cap_chunk, true),
415 DEFINE_PROP_BOOL("x-allow-chunk-migration", CRBState,
416 allow_chunk_migration, true),
417 };
418
419 static void tpm_crb_reset(void *dev)
420 {
421 CRBState *s = CRB(dev);
422
423 tpm_ppi_reset(&s->ppi);
424 tpm_backend_reset(s->tpmbe);
425 tpm_crb_clear_internal_buffers(s);
426
427 memset(s->regs, 0, sizeof(s->regs));
428
429 ARRAY_FIELD_DP32(s->regs, CRB_LOC_STATE,
430 tpmRegValidSts, 1);
431 ARRAY_FIELD_DP32(s->regs, CRB_CTRL_STS,
432 tpmIdle, 1);
433 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
434 InterfaceType, CRB_INTF_TYPE_CRB_ACTIVE);
435 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
436 InterfaceVersion, CRB_INTF_VERSION_CRB);
437 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
438 CapLocality, CRB_INTF_CAP_LOCALITY_0_ONLY);
439 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
440 CapCRBIdleBypass, CRB_INTF_CAP_IDLE_FAST);
441 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
442 CapDataXferSizeSupport, CRB_INTF_CAP_XFER_SIZE_64);
443 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
444 CapFIFO, CRB_INTF_CAP_FIFO_NOT_SUPPORTED);
445 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
446 CapCRB, CRB_INTF_CAP_CRB_SUPPORTED);
447 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
448 InterfaceSelector, CRB_INTF_IF_SELECTOR_CRB);
449 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
450 CapCRBChunk, s->cap_chunk ? CRB_INTF_CAP_CRB_CHUNK : 0);
451 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID,
452 RID, 0b0000);
453 ARRAY_FIELD_DP32(s->regs, CRB_INTF_ID2,
454 VID, PCI_VENDOR_ID_IBM);
455
456 s->regs[R_CRB_CTRL_CMD_SIZE] = CRB_CTRL_CMD_SIZE;
457 s->regs[R_CRB_CTRL_CMD_LADDR] = TPM_CRB_ADDR_BASE + A_CRB_DATA_BUFFER;
458 s->regs[R_CRB_CTRL_RSP_SIZE] = CRB_CTRL_CMD_SIZE;
459 s->regs[R_CRB_CTRL_RSP_ADDR] = TPM_CRB_ADDR_BASE + A_CRB_DATA_BUFFER;
460
461 s->be_buffer_size = tpm_backend_get_buffer_size(s->tpmbe);
462
463 if (tpm_backend_startup_tpm(s->tpmbe, s->be_buffer_size) < 0) {
464 exit(1);
465 }
466 }
467
468 static void tpm_crb_realize(DeviceState *dev, Error **errp)
469 {
470 CRBState *s = CRB(dev);
471 int ret;
472
473 if (!tpm_find()) {
474 error_setg(errp, "at most one TPM device is permitted");
475 return;
476 }
477 if (!s->tpmbe) {
478 error_setg(errp, "'tpmdev' property is required");
479 return;
480 }
481 if (s->cap_chunk && !s->allow_chunk_migration) {
482 error_setg(&s->migration_blocker,
483 "The tpm-crb device does not support chunk migration with "
484 "machine version less than 11.1");
485 ret = migrate_add_blocker_normal(&s->migration_blocker, errp);
486 if (ret < 0) {
487 return;
488 }
489 }
490
491 memory_region_init_io(&s->mmio, OBJECT(s), &tpm_crb_memory_ops, s,
492 "tpm-crb-mmio", sizeof(s->regs));
493 memory_region_init_ram(&s->cmdmem, OBJECT(s),
494 "tpm-crb-cmd", CRB_CTRL_CMD_SIZE, errp);
495
496 memory_region_add_subregion(get_system_memory(),
497 TPM_CRB_ADDR_BASE, &s->mmio);
498 memory_region_add_subregion(get_system_memory(),
499 TPM_CRB_ADDR_BASE + sizeof(s->regs), &s->cmdmem);
500
501 s->command_buffer = g_byte_array_new();
502 s->response_buffer = g_byte_array_new();
503
504 tpm_ppi_init(&s->ppi, get_system_memory(),
505 TPM_PPI_ADDR_BASE, OBJECT(s));
506
507 if (xen_enabled()) {
508 tpm_crb_reset(dev);
509 } else {
510 qemu_register_reset(tpm_crb_reset, dev);
511 }
512 }
513
514 static void tpm_crb_unrealize(DeviceState *dev)
515 {
516 CRBState *s = CRB(dev);
517
518 g_clear_pointer(&s->command_buffer, g_byte_array_unref);
519 g_clear_pointer(&s->response_buffer, g_byte_array_unref);
520
521 if (s->migration_blocker) {
522 migrate_del_blocker(&s->migration_blocker);
523 }
524 }
525
526 static void tpm_crb_class_init(ObjectClass *klass, const void *data)
527 {
528 DeviceClass *dc = DEVICE_CLASS(klass);
529 TPMIfClass *tc = TPM_IF_CLASS(klass);
530
531 dc->realize = tpm_crb_realize;
532 dc->unrealize = tpm_crb_unrealize;
533 device_class_set_props(dc, tpm_crb_properties);
534 dc->vmsd = &vmstate_tpm_crb;
535 dc->user_creatable = true;
536 tc->model = TPM_MODEL_TPM_CRB;
537 tc->ppi_enabled = true;
538 tc->get_version = tpm_crb_get_version;
539 tc->request_completed = tpm_crb_request_completed;
540
541 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
542 }
543
544 static const TypeInfo tpm_crb_info = {
545 .name = TYPE_TPM_CRB,
546 /* could be TYPE_SYS_BUS_DEVICE (or LPC etc) */
547 .parent = TYPE_DEVICE,
548 .instance_size = sizeof(CRBState),
549 .class_init = tpm_crb_class_init,
550 .interfaces = (const InterfaceInfo[]) {
551 { TYPE_TPM_IF },
552 { }
553 }
554 };
555
556 static void tpm_crb_register(void)
557 {
558 type_register_static(&tpm_crb_info);
559 }
560
561 type_init(tpm_crb_register)