+void unregister_savevm(const char *idstr, void *opaque)
+{
+ SaveStateEntry *se, *new_se;
+
+ QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
+ if (strcmp(se->idstr, idstr) == 0 && se->opaque == opaque) {
+ QTAILQ_REMOVE(&savevm_handlers, se, entry);
+ qemu_free(se);
+ }
+ }
+}
+
+int vmstate_register(int instance_id, const VMStateDescription *vmsd,
+ void *opaque)
+{
+ SaveStateEntry *se;
+
+ se = qemu_malloc(sizeof(SaveStateEntry));
+ pstrcpy(se->idstr, sizeof(se->idstr), vmsd->name);
+ se->version_id = vmsd->version_id;
+ se->section_id = global_section_id++;
+ se->save_live_state = NULL;
+ se->save_state = NULL;
+ se->load_state = NULL;
+ se->opaque = opaque;
+ se->vmsd = vmsd;
+
+ if (instance_id == -1) {
+ se->instance_id = calculate_new_instance_id(vmsd->name);
+ } else {
+ se->instance_id = instance_id;
+ }
+ /* add at the end of list */
+ QTAILQ_INSERT_TAIL(&savevm_handlers, se, entry);
+ return 0;
+}
+
+void vmstate_unregister(const VMStateDescription *vmsd, void *opaque)
+{
+ SaveStateEntry *se, *new_se;
+
+ QTAILQ_FOREACH_SAFE(se, &savevm_handlers, entry, new_se) {
+ if (se->vmsd == vmsd && se->opaque == opaque) {
+ QTAILQ_REMOVE(&savevm_handlers, se, entry);
+ qemu_free(se);
+ }
+ }
+}
+
+int vmstate_load_state(QEMUFile *f, const VMStateDescription *vmsd,
+ void *opaque, int version_id)
+{
+ VMStateField *field = vmsd->fields;
+
+ if (version_id > vmsd->version_id) {
+ return -EINVAL;
+ }
+ if (version_id < vmsd->minimum_version_id_old) {
+ return -EINVAL;
+ }
+ if (version_id < vmsd->minimum_version_id) {
+ return vmsd->load_state_old(f, opaque, version_id);
+ }
+ if (vmsd->pre_load) {
+ int ret = vmsd->pre_load(opaque);
+ if (ret)
+ return ret;
+ }
+ while(field->name) {
+ if (field->version_id <= version_id) {
+ void *base_addr = opaque + field->offset;
+ int ret, i, n_elems = 1;
+
+ if (field->flags & VMS_ARRAY) {
+ n_elems = field->num;
+ } else if (field->flags & VMS_VARRAY) {
+ n_elems = *(size_t *)(opaque+field->num_offset);
+ }
+ if (field->flags & VMS_POINTER) {
+ base_addr = *(void **)base_addr;
+ }
+ for (i = 0; i < n_elems; i++) {
+ void *addr = base_addr + field->size * i;
+
+ if (field->flags & VMS_STRUCT) {
+ ret = vmstate_load_state(f, field->vmsd, addr, field->vmsd->version_id);
+ } else {
+ ret = field->info->get(f, addr, field->size);
+
+ }
+ if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+ field++;
+ }
+ if (vmsd->post_load) {
+ return vmsd->post_load(opaque);
+ }
+ return 0;
+}
+
+void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd,
+ const void *opaque)
+{
+ VMStateField *field = vmsd->fields;
+
+ if (vmsd->pre_save) {
+ vmsd->pre_save(opaque);
+ }
+ while(field->name) {
+ const void *base_addr = opaque + field->offset;
+ int i, n_elems = 1;
+
+ if (field->flags & VMS_ARRAY) {
+ n_elems = field->num;
+ } else if (field->flags & VMS_VARRAY) {
+ n_elems = *(size_t *)(opaque+field->num_offset);
+ }
+ if (field->flags & VMS_POINTER) {
+ base_addr = *(void **)base_addr;
+ }
+ for (i = 0; i < n_elems; i++) {
+ const void *addr = base_addr + field->size * i;
+
+ if (field->flags & VMS_STRUCT) {
+ vmstate_save_state(f, field->vmsd, addr);
+ } else {
+ field->info->put(f, addr, field->size);
+ }
+ }
+ field++;
+ }
+ if (vmsd->post_save) {
+ vmsd->post_save(opaque);
+ }
+}
+
+static int vmstate_load(QEMUFile *f, SaveStateEntry *se, int version_id)
+{
+ if (!se->vmsd) { /* Old style */
+ return se->load_state(f, se->opaque, version_id);
+ }
+ return vmstate_load_state(f, se->vmsd, se->opaque, version_id);
+}
+
+static void vmstate_save(QEMUFile *f, SaveStateEntry *se)
+{
+ if (!se->vmsd) { /* Old style */
+ se->save_state(f, se->opaque);
+ return;
+ }
+ vmstate_save_state(f,se->vmsd, se->opaque);
+}
+