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"
51
TPMPPI ppi;
52
53
bool cap_chunk;
54
+ bool allow_chunk_migration;
55
+ Error *migration_blocker;
56
};
57
typedef struct CRBState CRBState;
58
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)
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");
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));
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)