diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c index 04716b5f6c..b9a88b2826 100644 --- a/hw/virtio/virtio.c +++ b/hw/virtio/virtio.c @@ -2807,7 +2807,9 @@ static int virtio_device_put(QEMUFile *f, void *opaque, size_t size, } /* A wrapper for use as a VMState .get function */ -static int virtio_device_get(QEMUFile *f, void *opaque, size_t size, +int virtio_device_get(QEMUFile *f, void *opaque, size_t size, + const VMStateField *field); +int virtio_device_get(QEMUFile *f, void *opaque, size_t size, const VMStateField *field) { VirtIODevice *vdev = VIRTIO_DEVICE(opaque); diff --git a/nyx/snapshot/devices/nyx_device_state.c b/nyx/snapshot/devices/nyx_device_state.c index 3911deb12c..098d9b7af8 100644 --- a/nyx/snapshot/devices/nyx_device_state.c +++ b/nyx/snapshot/devices/nyx_device_state.c @@ -376,6 +376,12 @@ nyx_device_state_t* nyx_device_state_init_from_snapshot(const char* snapshot_fol return self; } +/* + * This is where QemuFile is created for later fast_snapshot creation + * we use fast_qemu_savevm_state() to create a regular snapshot to QEMUFile + * backed by RAM. state_reallocation_new() then uses this file to build an + * optimized sequence of snapshot restore operations. + */ nyx_device_state_t* nyx_device_state_init(void){ nyx_device_state_t* self = malloc(sizeof(nyx_device_state_t)); diff --git a/nyx/snapshot/devices/state_reallocation.c b/nyx/snapshot/devices/state_reallocation.c index 666a207160..ab83f58acc 100644 --- a/nyx/snapshot/devices/state_reallocation.c +++ b/nyx/snapshot/devices/state_reallocation.c @@ -283,13 +283,45 @@ static void add_post_fptr(state_reallocation_t* self, void* fptr, uint32_t versi extern void fast_get_pci_config_device(void* data, size_t size, void* opaque); void fast_get_pci_irq_state(void* data, size_t size, void* opaque); +//void fast_virtio_device_get(void* data, size_t size, void* opaque); +int virtio_device_get(QEMUFile *f, void *opaque, size_t size, const VMStateField *field); + +static int fast_loadvm_fclose(void *opaque){ + return 0; +} + +static ssize_t fast_loadvm_get_buffer(void *opaque, uint8_t *buf, int64_t pos, size_t size){ + assert(pos < ((struct fast_savevm_opaque_t*)(opaque))->buflen); + memcpy(buf, (void*)(((struct fast_savevm_opaque_t*)(opaque))->buf + pos), size); + return size; +} + +static const QEMUFileOps fast_loadvm_ops = { + .get_buffer = (QEMUFileGetBufferFunc*)fast_loadvm_get_buffer, + .close = (QEMUFileCloseFunc*)fast_loadvm_fclose +}; + +/* use opaque data to bootstrap virtio restore from QEMUFile */ +static void fast_virtio_device_get(void* data, size_t size, void* opaque) +{ + struct fast_savevm_opaque_t fast_loadvm_opaque = { + .buf = data, + .buflen = size, + .f = NULL, + .pos = 0, + }; + QEMUFile* f = qemu_fopen_ops(&fast_loadvm_opaque, &fast_loadvm_ops); + + virtio_device_get(f, opaque, size, NULL); +} + static void add_get(state_reallocation_t* self, void* fptr, void* opaque, size_t size, void* field, QEMUFile* f, const char* name){ if(!self){ return; } void (*handler)(void* , size_t, void*) = NULL; - void* data = NULL; + uint8_t* data = NULL; if(!strcmp(name, "timer")){ debug_fprintf(stderr, "SKPPING: %ld\n", size*-1); @@ -315,13 +347,21 @@ static void add_get(state_reallocation_t* self, void* fptr, void* opaque, size_t data = malloc(sizeof(uint8_t)*size); qemu_get_buffer(f, (uint8_t*)data, size); } - + else if(!strcmp(name, "virtio")){ + fprintf(stderr, "WARNING: ATTEMPTING FAST GET for %s\n", name); + qemu_file_skip(f, size * -1); + handler = fast_virtio_device_get; + data = malloc(sizeof(uint8_t)*size); + qemu_get_buffer(f, (uint8_t*)data, size); + } else{ fprintf(stderr, "WARNING: NOT IMPLEMENTED FAST GET ROUTINE for %s\n", name); abort(); return; } + // will be called by pre-/post-save or pre-post-load? + // will be processed by fdl_fast_reload() self->get_fptr[self->fast_state_get_fptr_pos] = handler; self->get_opaque[self->fast_state_get_fptr_pos] = opaque; self->get_size[self->fast_state_get_fptr_pos] = size; @@ -481,19 +521,21 @@ static inline int get_handler(state_reallocation_t* self, QEMUFile* f, void* cur add_get(self, (void*) field->info->get, curr_elem, size, (void*) field, f, field->info->name); } else if(!strcmp(field->info->name, "pci config")){ - //fprintf(stderr, "type: %s (size: %x)\n", field->info->name, size); + fprintf(stderr, "type: %s (size: %lx)\n", field->info->name, size); add_get(self, (void*) field->info->get, curr_elem, size, (void*) field, f, field->info->name); } else if(!strcmp(field->info->name, "pci irq state")){ - //fprintf(stderr, "type: %s (size: %x)\n", field->info->name, size); + fprintf(stderr, "type: %s (size: %lx)\n", field->info->name, size); add_get(self, (void*) field->info->get, curr_elem, size, (void*) field, f, field->info->name); } else if(!strcmp(field->info->name, "virtio")){ - fprintf(stderr, "type: %s (size: %lx)\n", field->info->name, size); - abort(); /* not yet implemented */ + add_get(self, (void*) field->info->get, curr_elem, size, (void*) field, f, field->info->name); + //fprintf(stderr, "[QEMU-PT] %s: WARNING no handler for %s, type %s, size %lx!\n", + // __func__, vmsd_name, field->info->name, size); } else{ - fprintf(stderr, "FAIL field->info->name: %s\n", field->info->name); + fprintf(stderr, "[QEMU-PT] %s: WARNING no handler for %s, type %s, size %lx!\n", + __func__, vmsd_name, field->info->name, size); assert(0); } @@ -918,6 +960,7 @@ state_reallocation_t* state_reallocation_new(QEMUFile *f){ self->tmp_snapshot.enabled = false; self->tmp_snapshot.fast_state_size = 0; + // actually enumerate the devices here fdl_enumerate_global_states(self, f); self->tmp_snapshot.copy = malloc(sizeof(void*) * self->fast_state_pos); diff --git a/nyx/snapshot/devices/state_reallocation.h b/nyx/snapshot/devices/state_reallocation.h index 4d594d1fe2..539ff49095 100644 --- a/nyx/snapshot/devices/state_reallocation.h +++ b/nyx/snapshot/devices/state_reallocation.h @@ -50,6 +50,7 @@ struct QEMUFile_tmp { struct fast_savevm_opaque_t{ FILE* f; uint8_t* buf; + size_t buflen; uint64_t pos; void* output_buffer; uint32_t* output_buffer_size;