static void save_vmstate(const VMStateDescription *desc, void *obj) { QEMUFile *f = open_test_file(true); /* Save file with vmstate */ vmstate_save_state(f, desc, obj); qemu_put_byte(f, QEMU_VM_EOF); g_assert(!qemu_file_get_error(f)); qemu_fclose(f); }
void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque) { VMStateField *field = vmsd->fields; if (vmsd->pre_save) { vmsd->pre_save(opaque); } while (field->name) { if (!field->field_exists || field->field_exists(opaque, vmsd->version_id)) { void *base_addr = opaque + field->offset; int i, n_elems = 1; int size = field->size; if (field->flags & VMS_VBUFFER) { size = *(int32_t *)(opaque+field->size_offset); if (field->flags & VMS_MULTIPLY) { size *= field->size; } } if (field->flags & VMS_ARRAY) { n_elems = field->num; } else if (field->flags & VMS_VARRAY_INT32) { n_elems = *(int32_t *)(opaque+field->num_offset); } else if (field->flags & VMS_VARRAY_UINT32) { n_elems = *(uint32_t *)(opaque+field->num_offset); } else if (field->flags & VMS_VARRAY_UINT16) { n_elems = *(uint16_t *)(opaque+field->num_offset); } else if (field->flags & VMS_VARRAY_UINT8) { n_elems = *(uint8_t *)(opaque+field->num_offset); } if (field->flags & VMS_POINTER) { base_addr = *(void **)base_addr + field->start; } for (i = 0; i < n_elems; i++) { void *addr = base_addr + size * i; if (field->flags & VMS_ARRAY_OF_POINTER) { addr = *(void **)addr; } if (field->flags & VMS_STRUCT) { vmstate_save_state(f, field->vmsd, addr); } else { field->info->put(f, addr, size); } } } field++; } vmstate_subsection_save(f, vmsd, opaque); }
static int put_tmp(QEMUFile *f, void *pv, size_t size, VMStateField *field, QJSON *vmdesc) { const VMStateDescription *vmsd = field->vmsd; void *tmp = g_malloc(size); /* Writes the parent field which is at the start of the tmp */ *(void **)tmp = pv; vmstate_save_state(f, vmsd, tmp, vmdesc); g_free(tmp); return 0; }
static int vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, QJSON *vmdesc) { const VMStateDescription **sub = vmsd->subsections; bool subsection_found = false; int ret = 0; trace_vmstate_subsection_save_top(vmsd->name); while (sub && *sub) { if (vmstate_save_needed(*sub, opaque)) { const VMStateDescription *vmsdsub = *sub; uint8_t len; trace_vmstate_subsection_save_loop(vmsd->name, vmsdsub->name); if (vmdesc) { /* Only create subsection array when we have any */ if (!subsection_found) { json_start_array(vmdesc, "subsections"); subsection_found = true; } json_start_object(vmdesc, NULL); } qemu_put_byte(f, QEMU_VM_SUBSECTION); len = strlen(vmsdsub->name); qemu_put_byte(f, len); qemu_put_buffer(f, (uint8_t *)vmsdsub->name, len); qemu_put_be32(f, vmsdsub->version_id); ret = vmstate_save_state(f, vmsdsub, opaque, vmdesc); if (ret) { return ret; } if (vmdesc) { json_end_object(vmdesc); } } sub++; } if (vmdesc && subsection_found) { json_end_array(vmdesc); } return ret; }
static void vmstate_subsection_save(QEMUFile *f, const VMStateDescription *vmsd, void *opaque) { const VMStateSubsection *sub = vmsd->subsections; while (sub && sub->needed) { if (sub->needed(opaque)) { const VMStateDescription *vmsd = sub->vmsd; uint8_t len; qemu_put_byte(f, QEMU_VM_SUBSECTION); len = strlen(vmsd->name); qemu_put_byte(f, len); qemu_put_buffer(f, (uint8_t *)vmsd->name, len); qemu_put_be32(f, vmsd->version_id); vmstate_save_state(f, vmsd, opaque); } sub++; } }
void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque) { VMStateField *field = vmsd->fields; if (vmsd->pre_save) { vmsd->pre_save(opaque); } while (field->name) { if (!field->field_exists || field->field_exists(opaque, vmsd->version_id)) { void *base_addr = vmstate_base_addr(opaque, field); int i, n_elems = vmstate_n_elems(opaque, field); int size = vmstate_size(opaque, field); for (i = 0; i < n_elems; i++) { void *addr = base_addr + size * i; if (field->flags & VMS_ARRAY_OF_POINTER) { addr = *(void **)addr; } if (field->flags & VMS_STRUCT) { vmstate_save_state(f, field->vmsd, addr); } else { field->info->put(f, addr, size); } } } else { if (field->flags & VMS_MUST_EXIST) { fprintf(stderr, "Output state validation failed: %s/%s\n", vmsd->name, field->name); assert(!(field->flags & VMS_MUST_EXIST)); } } field++; } vmstate_subsection_save(f, vmsd, opaque); }
void cpu_save(QEMUFile *f, void *opaque) { vmstate_save_state(f, &vmstate_cpu, opaque); }
int vmstate_save_state_v(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, QJSON *vmdesc, int version_id) { int ret = 0; const VMStateField *field = vmsd->fields; trace_vmstate_save_state_top(vmsd->name); if (vmsd->pre_save) { ret = vmsd->pre_save(opaque); trace_vmstate_save_state_pre_save_res(vmsd->name, ret); if (ret) { error_report("pre-save failed: %s", vmsd->name); return ret; } } if (vmdesc) { json_prop_str(vmdesc, "vmsd_name", vmsd->name); json_prop_int(vmdesc, "version", version_id); json_start_array(vmdesc, "fields"); } while (field->name) { if ((field->field_exists && field->field_exists(opaque, version_id)) || (!field->field_exists && field->version_id <= version_id)) { void *first_elem = opaque + field->offset; int i, n_elems = vmstate_n_elems(opaque, field); int size = vmstate_size(opaque, field); int64_t old_offset, written_bytes; QJSON *vmdesc_loop = vmdesc; trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems); if (field->flags & VMS_POINTER) { first_elem = *(void **)first_elem; assert(first_elem || !n_elems || !size); } for (i = 0; i < n_elems; i++) { void *curr_elem = first_elem + size * i; ret = 0; vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems); old_offset = qemu_ftell_fast(f); if (field->flags & VMS_ARRAY_OF_POINTER) { assert(curr_elem); curr_elem = *(void **)curr_elem; } if (!curr_elem && size) { /* if null pointer write placeholder and do not follow */ assert(field->flags & VMS_ARRAY_OF_POINTER); ret = vmstate_info_nullptr.put(f, curr_elem, size, NULL, NULL); } else if (field->flags & VMS_STRUCT) { ret = vmstate_save_state(f, field->vmsd, curr_elem, vmdesc_loop); } else if (field->flags & VMS_VSTRUCT) { ret = vmstate_save_state_v(f, field->vmsd, curr_elem, vmdesc_loop, field->struct_version_id); } else { ret = field->info->put(f, curr_elem, size, field, vmdesc_loop); } if (ret) { error_report("Save of field %s/%s failed", vmsd->name, field->name); if (vmsd->post_save) { vmsd->post_save(opaque); } return ret; } written_bytes = qemu_ftell_fast(f) - old_offset; vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i); /* Compressed arrays only care about the first element */ if (vmdesc_loop && vmsd_can_compress(field)) { vmdesc_loop = NULL; } } } else { if (field->flags & VMS_MUST_EXIST) { error_report("Output state validation failed: %s/%s", vmsd->name, field->name); assert(!(field->flags & VMS_MUST_EXIST)); } } field++; } if (vmdesc) { json_end_array(vmdesc); } ret = vmstate_subsection_save(f, vmsd, opaque, vmdesc); if (vmsd->post_save) { int ps_ret = vmsd->post_save(opaque); if (!ret) { ret = ps_ret; } } return ret; }
void vmstate_save_state(QEMUFile *f, const VMStateDescription *vmsd, void *opaque, QJSON *vmdesc) { VMStateField *field = vmsd->fields; trace_vmstate_save_state_top(vmsd->name); if (vmsd->pre_save) { vmsd->pre_save(opaque); } if (vmdesc) { json_prop_str(vmdesc, "vmsd_name", vmsd->name); json_prop_int(vmdesc, "version", vmsd->version_id); json_start_array(vmdesc, "fields"); } while (field->name) { if (!field->field_exists || field->field_exists(opaque, vmsd->version_id)) { void *base_addr = vmstate_base_addr(opaque, field, false); int i, n_elems = vmstate_n_elems(opaque, field); int size = vmstate_size(opaque, field); int64_t old_offset, written_bytes; QJSON *vmdesc_loop = vmdesc; trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems); for (i = 0; i < n_elems; i++) { void *addr = base_addr + size * i; vmsd_desc_field_start(vmsd, vmdesc_loop, field, i, n_elems); old_offset = qemu_ftell_fast(f); if (field->flags & VMS_ARRAY_OF_POINTER) { addr = *(void **)addr; } if (field->flags & VMS_STRUCT) { vmstate_save_state(f, field->vmsd, addr, vmdesc_loop); } else { field->info->put(f, addr, size, field, vmdesc_loop); } written_bytes = qemu_ftell_fast(f) - old_offset; vmsd_desc_field_end(vmsd, vmdesc_loop, field, written_bytes, i); /* Compressed arrays only care about the first element */ if (vmdesc_loop && vmsd_can_compress(field)) { vmdesc_loop = NULL; } } } else { if (field->flags & VMS_MUST_EXIST) { error_report("Output state validation failed: %s/%s", vmsd->name, field->name); assert(!(field->flags & VMS_MUST_EXIST)); } } field++; } if (vmdesc) { json_end_array(vmdesc); } vmstate_subsection_save(f, vmsd, opaque, vmdesc); }