diff options
author | Tim Deegan <Tim.Deegan@xensource.com> | 2007-01-18 16:48:04 +0000 |
---|---|---|
committer | Tim Deegan <Tim.Deegan@xensource.com> | 2007-01-18 16:48:04 +0000 |
commit | 294b0bdd8b609d7e510b07b16a6351f7cfe265c1 (patch) | |
tree | 7c2f386bd9ea9338a03408d56c7a387928311911 /xen/arch/x86/hvm/intercept.c | |
parent | 4a13cf1b7005cc5022b67f2e96ab597108333704 (diff) | |
download | xen-294b0bdd8b609d7e510b07b16a6351f7cfe265c1.tar.gz xen-294b0bdd8b609d7e510b07b16a6351f7cfe265c1.tar.bz2 xen-294b0bdd8b609d7e510b07b16a6351f7cfe265c1.zip |
[HVM] save restore: new hyper-call
Signed-off-by: Zhai Edwin <edwin.zhai@intel.com>
add a pair of hyper-call for hvm guest context
Diffstat (limited to 'xen/arch/x86/hvm/intercept.c')
-rw-r--r-- | xen/arch/x86/hvm/intercept.c | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/xen/arch/x86/hvm/intercept.c b/xen/arch/x86/hvm/intercept.c index 3de58812c3..624dcbd0d4 100644 --- a/xen/arch/x86/hvm/intercept.c +++ b/xen/arch/x86/hvm/intercept.c @@ -29,6 +29,8 @@ #include <asm/current.h> #include <io_ports.h> #include <xen/event.h> +#include <xen/compile.h> +#include <public/version.h> extern struct hvm_mmio_handler hpet_mmio_handler; @@ -155,6 +157,235 @@ static inline void hvm_mmio_access(struct vcpu *v, } } +/* save/restore support */ +#define HVM_FILE_MAGIC 0x54381286 +#define HVM_FILE_VERSION 0x00000001 + +int hvm_register_savevm(struct domain *d, + const char *idstr, + int instance_id, + int version_id, + SaveStateHandler *save_state, + LoadStateHandler *load_state, + void *opaque) +{ + HVMStateEntry *se, **pse; + + if ( (se = xmalloc(struct HVMStateEntry)) == NULL ){ + printk("allocat hvmstate entry fail.\n"); + return -1; + } + + strncpy(se->idstr, idstr, HVM_SE_IDSTR_LEN); + + se->instance_id = instance_id; + se->version_id = version_id; + se->save_state = save_state; + se->load_state = load_state; + se->opaque = opaque; + se->next = NULL; + + /* add at the end of list */ + pse = &d->arch.hvm_domain.first_se; + while (*pse != NULL) + pse = &(*pse)->next; + *pse = se; + return 0; +} + +int hvm_save(struct vcpu *v, hvm_domain_context_t *h) +{ + uint32_t len, len_pos, cur_pos; + uint32_t eax, ebx, ecx, edx; + HVMStateEntry *se; + char *chgset; + + if (!is_hvm_vcpu(v)) { + printk("hvm_save only for hvm guest!\n"); + return -1; + } + + memset(h, 0, sizeof(hvm_domain_context_t)); + hvm_put_32u(h, HVM_FILE_MAGIC); + hvm_put_32u(h, HVM_FILE_VERSION); + + /* save xen changeset */ + chgset = strrchr(XEN_CHANGESET, ' ') + 1; + + len = strlen(chgset); + hvm_put_8u(h, len); + hvm_put_buffer(h, chgset, len); + + /* save cpuid */ + cpuid(1, &eax, &ebx, &ecx, &edx); + hvm_put_32u(h, eax); + + for(se = v->domain->arch.hvm_domain.first_se; se != NULL; se = se->next) { + /* ID string */ + len = strnlen(se->idstr, HVM_SE_IDSTR_LEN); + hvm_put_8u(h, len); + hvm_put_buffer(h, se->idstr, len); + + hvm_put_32u(h, se->instance_id); + hvm_put_32u(h, se->version_id); + + /* record size */ + len_pos = hvm_ctxt_tell(h); + hvm_put_32u(h, 0); + + se->save_state(h, se->opaque); + + cur_pos = hvm_ctxt_tell(h); + len = cur_pos - len_pos - 4; + hvm_ctxt_seek(h, len_pos); + hvm_put_32u(h, len); + hvm_ctxt_seek(h, cur_pos); + + } + + h->size = hvm_ctxt_tell(h); + hvm_ctxt_seek(h, 0); + + if (h->size >= HVM_CTXT_SIZE) { + printk("hvm_domain_context overflow when hvm_save! need %"PRId32" bytes for use.\n", h->size); + return -1; + } + + return 0; + +} + +static HVMStateEntry *find_se(struct domain *d, const char *idstr, int instance_id) +{ + HVMStateEntry *se; + + for(se = d->arch.hvm_domain.first_se; se != NULL; se = se->next) { + if (!strncmp(se->idstr, idstr, HVM_SE_IDSTR_LEN) && + instance_id == se->instance_id){ + return se; + } + } + return NULL; +} + +int hvm_load(struct vcpu *v, hvm_domain_context_t *h) +{ + uint32_t len, rec_len, rec_pos, magic, instance_id, version_id; + uint32_t eax, ebx, ecx, edx; + HVMStateEntry *se; + char idstr[HVM_SE_IDSTR_LEN]; + xen_changeset_info_t chgset; + char *cur_chgset; + int ret; + + if (!is_hvm_vcpu(v)) { + printk("hvm_load only for hvm guest!\n"); + return -1; + } + + if (h->size >= HVM_CTXT_SIZE) { + printk("hvm_load fail! seems hvm_domain_context overflow when hvm_save! need %"PRId32" bytes.\n", h->size); + return -1; + } + + hvm_ctxt_seek(h, 0); + + magic = hvm_get_32u(h); + if (magic != HVM_FILE_MAGIC) { + printk("HVM restore magic dismatch!\n"); + return -1; + } + + magic = hvm_get_32u(h); + if (magic != HVM_FILE_VERSION) { + printk("HVM restore version dismatch!\n"); + return -1; + } + + /* check xen change set */ + cur_chgset = strrchr(XEN_CHANGESET, ' ') + 1; + + len = hvm_get_8u(h); + if (len > 20) { /*typical length is 18 -- "revision number:changeset id" */ + printk("wrong change set length %d when hvm restore!\n", len); + return -1; + } + + hvm_get_buffer(h, chgset, len); + chgset[len] = '\0'; + if (strncmp(cur_chgset, chgset, len + 1)) + printk("warnings: try to restore hvm guest(%s) on a different changeset %s.\n", + chgset, cur_chgset); + + /* check cpuid */ + cpuid(1, &eax, &ebx, &ecx, &edx); + ebx = hvm_get_32u(h); + /*TODO: need difine how big difference is acceptable */ + if (ebx != eax) + printk("warnings: try to restore hvm guest(0x%"PRIx32") " + "on a different type processor(0x%"PRIx32").\n", + ebx, + eax); + + while(1) { + if (hvm_ctxt_end(h)) { + break; + } + + /* ID string */ + len = hvm_get_8u(h); + if (len > HVM_SE_IDSTR_LEN) { + printk("wrong HVM save entry idstr len %d!", len); + return -1; + } + + hvm_get_buffer(h, idstr, len); + idstr[len] = '\0'; + + instance_id = hvm_get_32u(h); + version_id = hvm_get_32u(h); + + rec_len = hvm_get_32u(h); + rec_pos = hvm_ctxt_tell(h); + + se = find_se(v->domain, idstr, instance_id); + if (se == NULL) { + printk("warnings: hvm load can't find device %s's instance %d!\n", + idstr, instance_id); + } else { + ret = se->load_state(h, se->opaque, version_id); + if (ret < 0) + printk("warnings: loading state fail for device %s instance %d!\n", + idstr, instance_id); + } + + + /* make sure to jump end of record */ + if ( hvm_ctxt_tell(h) - rec_pos != rec_len) { + printk("wrong hvm record size, maybe some dismatch between save&restore handler!\n"); + } + hvm_ctxt_seek(h, rec_pos + rec_len); + } + + return 0; +} + +int arch_gethvm_ctxt( + struct vcpu *v, struct hvm_domain_context *c) +{ + if ( !is_hvm_vcpu(v) ) + return -1; + + return hvm_save(v, c); + +} + +int arch_sethvm_ctxt( + struct vcpu *v, struct hvm_domain_context *c) +{ + return hvm_load(v, c); +} + int hvm_buffered_io_intercept(ioreq_t *p) { struct vcpu *v = current; |