int hvm_save(struct domain *d, hvm_domain_context_t *h) { char *c; struct hvm_save_header hdr; struct hvm_save_end end; hvm_save_handler handler; uint16_t i; hdr.magic = HVM_FILE_MAGIC; hdr.version = HVM_FILE_VERSION; /* Save xen changeset */ c = strrchr(xen_changeset(), ':'); if ( c ) hdr.changeset = simple_strtoll(c, NULL, 16); else hdr.changeset = -1ULL; /* Unknown */ arch_hvm_save(d, &hdr); if ( hvm_save_entry(HEADER, 0, h, &hdr) != 0 ) { gdprintk(XENLOG_ERR, "HVM save: failed to write header\n"); return -EFAULT; } /* Save all available kinds of state */ for ( i = 0; i <= HVM_SAVE_CODE_MAX; i++ ) { handler = hvm_sr_handlers[i].save; if ( handler != NULL ) { gdprintk(XENLOG_INFO, "HVM save: %s\n", hvm_sr_handlers[i].name); if ( handler(d, h) != 0 ) { gdprintk(XENLOG_ERR, "HVM save: failed to save type %"PRIu16"\n", i); return -EFAULT; } } } /* Save an end-of-file marker */ if ( hvm_save_entry(END, 0, h, &end) != 0 ) { /* Run out of data */ gdprintk(XENLOG_ERR, "HVM save: no room for end marker.\n"); return -EFAULT; } /* Save macros should not have let us overrun */ ASSERT(h->cur <= h->size); return 0; }
/* Set up the single Xen-specific-info crash note. */ crash_xen_info_t *kexec_crash_save_info(void) { int cpu = smp_processor_id(); crash_xen_info_t info; crash_xen_info_t *out = (crash_xen_info_t *)ELFNOTE_DESC(xen_crash_note); BUG_ON(!cpu_test_and_set(cpu, crash_saved_cpus)); memset(&info, 0, sizeof(info)); info.xen_major_version = xen_major_version(); info.xen_minor_version = xen_minor_version(); info.xen_extra_version = __pa(xen_extra_version()); info.xen_changeset = __pa(xen_changeset()); info.xen_compiler = __pa(xen_compiler()); info.xen_compile_date = __pa(xen_compile_date()); info.xen_compile_time = __pa(xen_compile_time()); info.tainted = tainted; /* Copy from guaranteed-aligned local copy to possibly-unaligned dest. */ memcpy(out, &info, sizeof(info)); return out; }
int hvm_load(struct domain *d, hvm_domain_context_t *h) { char *c; uint64_t cset; struct hvm_save_header hdr; struct hvm_save_descriptor *desc; hvm_load_handler handler; struct vcpu *v; /* Read the save header, which must be first */ if ( hvm_load_entry(HEADER, h, &hdr) != 0 ) return -1; if ( arch_hvm_load(d, &hdr) ) return -1; c = strrchr(xen_changeset(), ':'); if ( hdr.changeset == -1ULL ) gdprintk(XENLOG_WARNING, "HVM restore: Xen changeset was not saved.\n"); else if ( c == NULL ) gdprintk(XENLOG_WARNING, "HVM restore: Xen changeset is not available.\n"); else { cset = simple_strtoll(c, NULL, 16); if ( hdr.changeset != cset ) gdprintk(XENLOG_WARNING, "HVM restore: saved Xen changeset (%#"PRIx64 ") does not match host (%#"PRIx64").\n", hdr.changeset, cset); } /* Down all the vcpus: we only re-enable the ones that had state saved. */ for_each_vcpu(d, v) if ( test_and_set_bit(_VPF_down, &v->pause_flags) ) vcpu_sleep_nosync(v); for ( ; ; ) { if ( h->size - h->cur < sizeof(struct hvm_save_descriptor) ) { /* Run out of data */ gdprintk(XENLOG_ERR, "HVM restore: save did not end with a null entry\n"); return -1; } /* Read the typecode of the next entry and check for the end-marker */ desc = (struct hvm_save_descriptor *)(&h->data[h->cur]); if ( desc->typecode == 0 ) return 0; /* Find the handler for this entry */ if ( (desc->typecode > HVM_SAVE_CODE_MAX) || ((handler = hvm_sr_handlers[desc->typecode].load) == NULL) ) { gdprintk(XENLOG_ERR, "HVM restore: unknown entry typecode %u\n", desc->typecode); return -1; } /* Load the entry */ gdprintk(XENLOG_INFO, "HVM restore: %s %"PRIu16"\n", hvm_sr_handlers[desc->typecode].name, desc->instance); if ( handler(d, h) != 0 ) { gdprintk(XENLOG_ERR, "HVM restore: failed to load entry %u/%u\n", desc->typecode, desc->instance); return -1; } } /* Not reached */ }