Zhai, Edwin
2007-Jan-11 14:08 UTC
[Xen-devel] [PATCH 2/8] HVM save restore: new hyper-call
[PATCH 2/8] 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 diff -r 7a38592d0cc9 tools/libxc/xc_domain.c --- a/tools/libxc/xc_domain.c Tue Jan 09 15:33:30 2007 +0800 +++ b/tools/libxc/xc_domain.c Tue Jan 09 15:37:58 2007 +0800 @@ -233,6 +233,50 @@ int xc_domain_getinfolist(int xc_handle, unlock_pages(info, max_domains*sizeof(xc_domaininfo_t)); return ret; +} + +/* get info from hvm guest for save */ +int xc_domain_hvm_getcontext(int xc_handle, + uint32_t domid, + hvm_domain_context_t *hvm_ctxt) +{ + int rc; + DECLARE_DOMCTL; + + domctl.cmd = XEN_DOMCTL_gethvmcontext; + domctl.domain = (domid_t)domid; + set_xen_guest_handle(domctl.u.hvmcontext.ctxt, hvm_ctxt); + + if ( (rc = mlock(hvm_ctxt, sizeof(*hvm_ctxt))) != 0 ) + return rc; + + rc = do_domctl(xc_handle, &domctl); + + safe_munlock(hvm_ctxt, sizeof(*hvm_ctxt)); + + return rc; +} + +/* set info to hvm guest for restore */ +int xc_domain_hvm_setcontext(int xc_handle, + uint32_t domid, + hvm_domain_context_t *hvm_ctxt) +{ + int rc; + DECLARE_DOMCTL; + + domctl.cmd = XEN_DOMCTL_sethvmcontext; + domctl.domain = domid; + set_xen_guest_handle(domctl.u.hvmcontext.ctxt, hvm_ctxt); + + if ( (rc = mlock(hvm_ctxt, sizeof(*hvm_ctxt))) != 0 ) + return rc; + + rc = do_domctl(xc_handle, &domctl); + + safe_munlock(hvm_ctxt, sizeof(*hvm_ctxt)); + + return rc; } int xc_vcpu_getcontext(int xc_handle, diff -r 7a38592d0cc9 tools/libxc/xenctrl.h --- a/tools/libxc/xenctrl.h Tue Jan 09 15:33:30 2007 +0800 +++ b/tools/libxc/xenctrl.h Tue Jan 09 15:37:58 2007 +0800 @@ -313,6 +313,30 @@ int xc_domain_getinfolist(int xc_handle, xc_domaininfo_t *info); /** + * This function returns information about the context of a hvm domain + * @parm xc_handle a handle to an open hypervisor interface + * @parm domid the domain to get information from + * @parm hvm_ctxt a pointer to a structure to store the execution context of the + * hvm domain + * @return 0 on success, -1 on failure + */ +int xc_domain_hvm_getcontext(int xc_handle, + uint32_t domid, + hvm_domain_context_t *hvm_ctxt); + +/** + * This function will set the context for hvm domain + * + * @parm xc_handle a handle to an open hypervisor interface + * @parm domid the domain to set the hvm domain context for + * @parm hvm_ctxt pointer to the the hvm context with the values to set + * @return 0 on success, -1 on failure + */ +int xc_domain_hvm_setcontext(int xc_handle, + uint32_t domid, + hvm_domain_context_t *hvm_ctxt); + +/** * This function returns information about the execution context of a * particular vcpu of a domain. * diff -r 7a38592d0cc9 xen/arch/x86/hvm/hvm.c --- a/xen/arch/x86/hvm/hvm.c Tue Jan 09 15:33:30 2007 +0800 +++ b/xen/arch/x86/hvm/hvm.c Thu Jan 11 21:00:37 2007 +0800 @@ -149,11 +149,19 @@ int hvm_domain_initialise(struct domain void hvm_domain_destroy(struct domain *d) { + HVMStateEntry *se, *dse; pit_deinit(d); rtc_deinit(d); pmtimer_deinit(d); hpet_deinit(d); + se = d->arch.hvm_domain.first_se; + while (se) { + dse = se; + se = se->next; + xfree(dse); + } + if ( d->arch.hvm_domain.shared_page_va ) unmap_domain_page_global( (void *)d->arch.hvm_domain.shared_page_va); diff -r 7a38592d0cc9 xen/arch/x86/hvm/intercept.c --- a/xen/arch/x86/hvm/intercept.c Tue Jan 09 15:33:30 2007 +0800 +++ b/xen/arch/x86/hvm/intercept.c Thu Jan 11 21:00:37 2007 +0800 @@ -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(struc } } +/* 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; diff -r 7a38592d0cc9 xen/common/domctl.c --- a/xen/common/domctl.c Tue Jan 09 15:33:30 2007 +0800 +++ b/xen/common/domctl.c Thu Jan 11 21:01:31 2007 +0800 @@ -215,6 +215,39 @@ ret_t do_domctl(XEN_GUEST_HANDLE(xen_dom } break; + case XEN_DOMCTL_sethvmcontext: + { + struct hvm_domain_context *c; + struct domain *d; + struct vcpu *v; + + ret = -ESRCH; + if ( (d = find_domain_by_id(op->domain)) == NULL ) + break; + + ret = -ENOMEM; + if ( (c = xmalloc(struct hvm_domain_context)) == NULL ) + goto sethvmcontext_out; + + v = d->vcpu[0]; + + ret = -EFAULT; + +#ifndef CONFIG_COMPAT + if ( copy_from_guest(c, op->u.hvmcontext.ctxt, 1) != 0 ) + goto sethvmcontext_out; + + ret = arch_sethvm_ctxt(v, c); +#endif + + xfree(c); + + sethvmcontext_out: + put_domain(d); + + } + break; + case XEN_DOMCTL_pausedomain: { struct domain *d = find_domain_by_id(op->domain); @@ -552,6 +585,46 @@ ret_t do_domctl(XEN_GUEST_HANDLE(xen_dom } break; + case XEN_DOMCTL_gethvmcontext: + { + struct hvm_domain_context *c; + struct domain *d; + struct vcpu *v; + + ret = -ESRCH; + if ( (d = find_domain_by_id(op->domain)) == NULL ) + break; + + ret = -ENOMEM; + if ( (c = xmalloc(struct hvm_domain_context)) == NULL ) + goto gethvmcontext_out; + + v = d->vcpu[0]; + + ret = -ENODATA; + if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) ) + goto gethvmcontext_out; + + ret = 0; + if (arch_gethvm_ctxt(v, c) == -1) + ret = -EFAULT; + +#ifndef CONFIG_COMPAT + if ( copy_to_guest(op->u.hvmcontext.ctxt, c, 1) ) + ret = -EFAULT; + + xfree(c); +#endif + + if ( copy_to_guest(u_domctl, op, 1) ) + ret = -EFAULT; + + gethvmcontext_out: + put_domain(d); + + } + break; + case XEN_DOMCTL_getvcpuinfo: { struct domain *d; diff -r 7a38592d0cc9 xen/include/asm-x86/hvm/domain.h --- a/xen/include/asm-x86/hvm/domain.h Tue Jan 09 15:33:30 2007 +0800 +++ b/xen/include/asm-x86/hvm/domain.h Tue Jan 09 15:37:58 2007 +0800 @@ -27,6 +27,20 @@ #include <asm/hvm/io.h> #include <public/hvm/params.h> +typedef void SaveStateHandler(hvm_domain_context_t *h, void *opaque); +typedef int LoadStateHandler(hvm_domain_context_t *h, void *opaque, int version_id); + +#define HVM_SE_IDSTR_LEN 32 +typedef struct HVMStateEntry { + char idstr[HVM_SE_IDSTR_LEN]; + int instance_id; + int version_id; + SaveStateHandler *save_state; + LoadStateHandler *load_state; + void *opaque; + struct HVMStateEntry *next; +} HVMStateEntry; + struct hvm_domain { unsigned long shared_page_va; unsigned long buffered_io_va; @@ -44,6 +58,9 @@ struct hvm_domain { spinlock_t pbuf_lock; uint64_t params[HVM_NR_PARAMS]; + + struct hvm_domain_context *hvm_ctxt; + HVMStateEntry *first_se; }; #endif /* __ASM_X86_HVM_DOMAIN_H__ */ diff -r 7a38592d0cc9 xen/include/asm-x86/hvm/support.h --- a/xen/include/asm-x86/hvm/support.h Tue Jan 09 15:33:30 2007 +0800 +++ b/xen/include/asm-x86/hvm/support.h Thu Jan 11 21:00:37 2007 +0800 @@ -121,6 +121,131 @@ extern unsigned int opt_hvm_debug_level; #define TRACE_VMEXIT(index, value) \ current->arch.hvm_vcpu.hvm_trace_values[index] = (value) +/* save/restore support */ + +//#define HVM_DEBUG_SUSPEND + +extern int hvm_register_savevm(struct domain *d, + const char *idstr, + int instance_id, + int version_id, + SaveStateHandler *save_state, + LoadStateHandler *load_state, + void *opaque); + +static inline void hvm_ctxt_seek(hvm_domain_context_t *h, unsigned int pos) +{ + h->cur = pos; +} + +static inline uint32_t hvm_ctxt_tell(hvm_domain_context_t *h) +{ + return h->cur; +} + +static inline int hvm_ctxt_end(hvm_domain_context_t *h) +{ + return (h->cur >= h->size || h->cur >= HVM_CTXT_SIZE); +} + +static inline void hvm_put_byte(hvm_domain_context_t *h, unsigned int i) +{ + if (h->cur >= HVM_CTXT_SIZE) { + h->cur++; + return; + } + h->data[h->cur++] = (char)i; +} + +static inline void hvm_put_8u(hvm_domain_context_t *h, uint8_t b) +{ + hvm_put_byte(h, b); +} + +static inline void hvm_put_16u(hvm_domain_context_t *h, uint16_t b) +{ + hvm_put_8u(h, b >> 8); + hvm_put_8u(h, b); +} + +static inline void hvm_put_32u(hvm_domain_context_t *h, uint32_t b) +{ + hvm_put_16u(h, b >> 16); + hvm_put_16u(h, b); +} + +static inline void hvm_put_64u(hvm_domain_context_t *h, uint64_t b) +{ + hvm_put_32u(h, b >> 32); + hvm_put_32u(h, b); +} + +static inline void hvm_put_buffer(hvm_domain_context_t *h, const char *buf, int len) +{ + memcpy(&h->data[h->cur], buf, len); + h->cur += len; +} + + +static inline char hvm_get_byte(hvm_domain_context_t *h) +{ + if (h->cur >= HVM_CTXT_SIZE) { + printk("hvm_get_byte overflow.\n"); + return -1; + } + + if (h->cur >= h->size) { + printk("hvm_get_byte exceed data area.\n"); + return -1; + } + + return h->data[h->cur++]; +} + +static inline uint8_t hvm_get_8u(hvm_domain_context_t *h) +{ + return hvm_get_byte(h); +} + +static inline uint16_t hvm_get_16u(hvm_domain_context_t *h) +{ + uint16_t v; + v = hvm_get_8u(h) << 8; + v |= hvm_get_8u(h); + + return v; +} + +static inline uint32_t hvm_get_32u(hvm_domain_context_t *h) +{ + uint32_t v; + v = hvm_get_16u(h) << 16; + v |= hvm_get_16u(h); + + return v; +} + +static inline uint64_t hvm_get_64u(hvm_domain_context_t *h) +{ + uint64_t v; + v = (uint64_t)hvm_get_32u(h) << 32; + v |= hvm_get_32u(h); + + return v; +} + +static inline void hvm_get_buffer(hvm_domain_context_t *h, char *buf, int len) +{ + memcpy(buf, &h->data[h->cur], len); + h->cur += len; +} + +extern int hvm_save(struct vcpu*, hvm_domain_context_t *h); +extern int hvm_load(struct vcpu*, hvm_domain_context_t *h); + +extern int arch_sethvm_ctxt(struct vcpu *v, struct hvm_domain_context *c); +extern int arch_gethvm_ctxt(struct vcpu *v, struct hvm_domain_context *c); + extern int hvm_enabled; int hvm_copy_to_guest_phys(paddr_t paddr, void *buf, int size); diff -r 7a38592d0cc9 xen/include/public/domctl.h --- a/xen/include/public/domctl.h Tue Jan 09 15:33:30 2007 +0800 +++ b/xen/include/public/domctl.h Tue Jan 09 15:37:58 2007 +0800 @@ -386,6 +386,21 @@ struct xen_domctl_settimeoffset { }; typedef struct xen_domctl_settimeoffset xen_domctl_settimeoffset_t; DEFINE_XEN_GUEST_HANDLE(xen_domctl_settimeoffset_t); + +#define HVM_CTXT_SIZE 6144 +typedef struct hvm_domain_context { + uint32_t cur; + uint32_t size; + uint8_t data[HVM_CTXT_SIZE]; +} hvm_domain_context_t; +DEFINE_XEN_GUEST_HANDLE(hvm_domain_context_t); + +#define XEN_DOMCTL_gethvmcontext 33 +#define XEN_DOMCTL_sethvmcontext 34 +typedef struct xen_domctl_hvmcontext { + XEN_GUEST_HANDLE(hvm_domain_context_t) ctxt; /* IN/OUT */ +} xen_domctl_hvmcontext_t; +DEFINE_XEN_GUEST_HANDLE(xen_domctl_hvmcontext_t); #define XEN_DOMCTL_real_mode_area 26 struct xen_domctl_real_mode_area { @@ -423,6 +438,7 @@ struct xen_domctl { struct xen_domctl_arch_setup arch_setup; struct xen_domctl_settimeoffset settimeoffset; struct xen_domctl_real_mode_area real_mode_area; + struct xen_domctl_hvmcontext hvmcontext; uint8_t pad[128]; } u; }; _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Anthony Liguori
2007-Jan-11 17:29 UTC
[Xen-devel] Re: [PATCH 2/8] HVM save restore: new hyper-call
Zhai, Edwin wrote:> [PATCH 2/8] 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 > > diff -r 7a38592d0cc9 tools/libxc/xc_domain.c > --- a/tools/libxc/xc_domain.c Tue Jan 09 15:33:30 2007 +0800 > +++ b/tools/libxc/xc_domain.c Tue Jan 09 15:37:58 2007 +0800 > @@ -233,6 +233,50 @@ int xc_domain_getinfolist(int xc_handle, > unlock_pages(info, max_domains*sizeof(xc_domaininfo_t)); > > return ret; > +} > + > +/* get info from hvm guest for save */ > +int xc_domain_hvm_getcontext(int xc_handle, > + uint32_t domid, > + hvm_domain_context_t *hvm_ctxt) > +{ > + int rc; > + DECLARE_DOMCTL; > + > + domctl.cmd = XEN_DOMCTL_gethvmcontext; > + domctl.domain = (domid_t)domid; > + set_xen_guest_handle(domctl.u.hvmcontext.ctxt, hvm_ctxt); > + > + if ( (rc = mlock(hvm_ctxt, sizeof(*hvm_ctxt))) != 0 ) > + return rc; > + > + rc = do_domctl(xc_handle, &domctl); > + > + safe_munlock(hvm_ctxt, sizeof(*hvm_ctxt)); > + > + return rc; > +} > + > +/* set info to hvm guest for restore */ > +int xc_domain_hvm_setcontext(int xc_handle, > + uint32_t domid, > + hvm_domain_context_t *hvm_ctxt) > +{ > + int rc; > + DECLARE_DOMCTL; > + > + domctl.cmd = XEN_DOMCTL_sethvmcontext; > + domctl.domain = domid; > + set_xen_guest_handle(domctl.u.hvmcontext.ctxt, hvm_ctxt); > + > + if ( (rc = mlock(hvm_ctxt, sizeof(*hvm_ctxt))) != 0 ) > + return rc; > + > + rc = do_domctl(xc_handle, &domctl); > + > + safe_munlock(hvm_ctxt, sizeof(*hvm_ctxt)); > + > + return rc; > }Perhaps these should be lock_pages instead of calling mlock() directly? Regards, Anthony Liguori> int xc_vcpu_getcontext(int xc_handle, > diff -r 7a38592d0cc9 tools/libxc/xenctrl.h > --- a/tools/libxc/xenctrl.h Tue Jan 09 15:33:30 2007 +0800 > +++ b/tools/libxc/xenctrl.h Tue Jan 09 15:37:58 2007 +0800 > @@ -313,6 +313,30 @@ int xc_domain_getinfolist(int xc_handle, > xc_domaininfo_t *info); > > /** > + * This function returns information about the context of a hvm domain > + * @parm xc_handle a handle to an open hypervisor interface > + * @parm domid the domain to get information from > + * @parm hvm_ctxt a pointer to a structure to store the execution context of the > + * hvm domain > + * @return 0 on success, -1 on failure > + */ > +int xc_domain_hvm_getcontext(int xc_handle, > + uint32_t domid, > + hvm_domain_context_t *hvm_ctxt); > + > +/** > + * This function will set the context for hvm domain > + * > + * @parm xc_handle a handle to an open hypervisor interface > + * @parm domid the domain to set the hvm domain context for > + * @parm hvm_ctxt pointer to the the hvm context with the values to set > + * @return 0 on success, -1 on failure > + */ > +int xc_domain_hvm_setcontext(int xc_handle, > + uint32_t domid, > + hvm_domain_context_t *hvm_ctxt); > + > +/** > * This function returns information about the execution context of a > * particular vcpu of a domain. > * > diff -r 7a38592d0cc9 xen/arch/x86/hvm/hvm.c > --- a/xen/arch/x86/hvm/hvm.c Tue Jan 09 15:33:30 2007 +0800 > +++ b/xen/arch/x86/hvm/hvm.c Thu Jan 11 21:00:37 2007 +0800 > @@ -149,11 +149,19 @@ int hvm_domain_initialise(struct domain > > void hvm_domain_destroy(struct domain *d) > { > + HVMStateEntry *se, *dse; > pit_deinit(d); > rtc_deinit(d); > pmtimer_deinit(d); > hpet_deinit(d); > > + se = d->arch.hvm_domain.first_se; > + while (se) { > + dse = se; > + se = se->next; > + xfree(dse); > + } > + > if ( d->arch.hvm_domain.shared_page_va ) > unmap_domain_page_global( > (void *)d->arch.hvm_domain.shared_page_va); > diff -r 7a38592d0cc9 xen/arch/x86/hvm/intercept.c > --- a/xen/arch/x86/hvm/intercept.c Tue Jan 09 15:33:30 2007 +0800 > +++ b/xen/arch/x86/hvm/intercept.c Thu Jan 11 21:00:37 2007 +0800 > @@ -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(struc > } > } > > +/* 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; > diff -r 7a38592d0cc9 xen/common/domctl.c > --- a/xen/common/domctl.c Tue Jan 09 15:33:30 2007 +0800 > +++ b/xen/common/domctl.c Thu Jan 11 21:01:31 2007 +0800 > @@ -215,6 +215,39 @@ ret_t do_domctl(XEN_GUEST_HANDLE(xen_dom > } > break; > > + case XEN_DOMCTL_sethvmcontext: > + { > + struct hvm_domain_context *c; > + struct domain *d; > + struct vcpu *v; > + > + ret = -ESRCH; > + if ( (d = find_domain_by_id(op->domain)) == NULL ) > + break; > + > + ret = -ENOMEM; > + if ( (c = xmalloc(struct hvm_domain_context)) == NULL ) > + goto sethvmcontext_out; > + > + v = d->vcpu[0]; > + > + ret = -EFAULT; > + > +#ifndef CONFIG_COMPAT > + if ( copy_from_guest(c, op->u.hvmcontext.ctxt, 1) != 0 ) > + goto sethvmcontext_out; > + > + ret = arch_sethvm_ctxt(v, c); > +#endif > + > + xfree(c); > + > + sethvmcontext_out: > + put_domain(d); > + > + } > + break; > + > case XEN_DOMCTL_pausedomain: > { > struct domain *d = find_domain_by_id(op->domain); > @@ -552,6 +585,46 @@ ret_t do_domctl(XEN_GUEST_HANDLE(xen_dom > } > break; > > + case XEN_DOMCTL_gethvmcontext: > + { > + struct hvm_domain_context *c; > + struct domain *d; > + struct vcpu *v; > + > + ret = -ESRCH; > + if ( (d = find_domain_by_id(op->domain)) == NULL ) > + break; > + > + ret = -ENOMEM; > + if ( (c = xmalloc(struct hvm_domain_context)) == NULL ) > + goto gethvmcontext_out; > + > + v = d->vcpu[0]; > + > + ret = -ENODATA; > + if ( !test_bit(_VCPUF_initialised, &v->vcpu_flags) ) > + goto gethvmcontext_out; > + > + ret = 0; > + if (arch_gethvm_ctxt(v, c) == -1) > + ret = -EFAULT; > + > +#ifndef CONFIG_COMPAT > + if ( copy_to_guest(op->u.hvmcontext.ctxt, c, 1) ) > + ret = -EFAULT; > + > + xfree(c); > +#endif > + > + if ( copy_to_guest(u_domctl, op, 1) ) > + ret = -EFAULT; > + > + gethvmcontext_out: > + put_domain(d); > + > + } > + break; > + > case XEN_DOMCTL_getvcpuinfo: > { > struct domain *d; > diff -r 7a38592d0cc9 xen/include/asm-x86/hvm/domain.h > --- a/xen/include/asm-x86/hvm/domain.h Tue Jan 09 15:33:30 2007 +0800 > +++ b/xen/include/asm-x86/hvm/domain.h Tue Jan 09 15:37:58 2007 +0800 > @@ -27,6 +27,20 @@ > #include <asm/hvm/io.h> > #include <public/hvm/params.h> > > +typedef void SaveStateHandler(hvm_domain_context_t *h, void *opaque); > +typedef int LoadStateHandler(hvm_domain_context_t *h, void *opaque, int version_id); > + > +#define HVM_SE_IDSTR_LEN 32 > +typedef struct HVMStateEntry { > + char idstr[HVM_SE_IDSTR_LEN]; > + int instance_id; > + int version_id; > + SaveStateHandler *save_state; > + LoadStateHandler *load_state; > + void *opaque; > + struct HVMStateEntry *next; > +} HVMStateEntry; > + > struct hvm_domain { > unsigned long shared_page_va; > unsigned long buffered_io_va; > @@ -44,6 +58,9 @@ struct hvm_domain { > spinlock_t pbuf_lock; > > uint64_t params[HVM_NR_PARAMS]; > + > + struct hvm_domain_context *hvm_ctxt; > + HVMStateEntry *first_se; > }; > > #endif /* __ASM_X86_HVM_DOMAIN_H__ */ > diff -r 7a38592d0cc9 xen/include/asm-x86/hvm/support.h > --- a/xen/include/asm-x86/hvm/support.h Tue Jan 09 15:33:30 2007 +0800 > +++ b/xen/include/asm-x86/hvm/support.h Thu Jan 11 21:00:37 2007 +0800 > @@ -121,6 +121,131 @@ extern unsigned int opt_hvm_debug_level; > #define TRACE_VMEXIT(index, value) \ > current->arch.hvm_vcpu.hvm_trace_values[index] = (value) > > +/* save/restore support */ > + > +//#define HVM_DEBUG_SUSPEND > + > +extern int hvm_register_savevm(struct domain *d, > + const char *idstr, > + int instance_id, > + int version_id, > + SaveStateHandler *save_state, > + LoadStateHandler *load_state, > + void *opaque); > + > +static inline void hvm_ctxt_seek(hvm_domain_context_t *h, unsigned int pos) > +{ > + h->cur = pos; > +} > + > +static inline uint32_t hvm_ctxt_tell(hvm_domain_context_t *h) > +{ > + return h->cur; > +} > + > +static inline int hvm_ctxt_end(hvm_domain_context_t *h) > +{ > + return (h->cur >= h->size || h->cur >= HVM_CTXT_SIZE); > +} > + > +static inline void hvm_put_byte(hvm_domain_context_t *h, unsigned int i) > +{ > + if (h->cur >= HVM_CTXT_SIZE) { > + h->cur++; > + return; > + } > + h->data[h->cur++] = (char)i; > +} > + > +static inline void hvm_put_8u(hvm_domain_context_t *h, uint8_t b) > +{ > + hvm_put_byte(h, b); > +} > + > +static inline void hvm_put_16u(hvm_domain_context_t *h, uint16_t b) > +{ > + hvm_put_8u(h, b >> 8); > + hvm_put_8u(h, b); > +} > + > +static inline void hvm_put_32u(hvm_domain_context_t *h, uint32_t b) > +{ > + hvm_put_16u(h, b >> 16); > + hvm_put_16u(h, b); > +} > + > +static inline void hvm_put_64u(hvm_domain_context_t *h, uint64_t b) > +{ > + hvm_put_32u(h, b >> 32); > + hvm_put_32u(h, b); > +} > + > +static inline void hvm_put_buffer(hvm_domain_context_t *h, const char *buf, int len) > +{ > + memcpy(&h->data[h->cur], buf, len); > + h->cur += len; > +} > + > + > +static inline char hvm_get_byte(hvm_domain_context_t *h) > +{ > + if (h->cur >= HVM_CTXT_SIZE) { > + printk("hvm_get_byte overflow.\n"); > + return -1; > + } > + > + if (h->cur >= h->size) { > + printk("hvm_get_byte exceed data area.\n"); > + return -1; > + } > + > + return h->data[h->cur++]; > +} > + > +static inline uint8_t hvm_get_8u(hvm_domain_context_t *h) > +{ > + return hvm_get_byte(h); > +} > + > +static inline uint16_t hvm_get_16u(hvm_domain_context_t *h) > +{ > + uint16_t v; > + v = hvm_get_8u(h) << 8; > + v |= hvm_get_8u(h); > + > + return v; > +} > + > +static inline uint32_t hvm_get_32u(hvm_domain_context_t *h) > +{ > + uint32_t v; > + v = hvm_get_16u(h) << 16; > + v |= hvm_get_16u(h); > + > + return v; > +} > + > +static inline uint64_t hvm_get_64u(hvm_domain_context_t *h) > +{ > + uint64_t v; > + v = (uint64_t)hvm_get_32u(h) << 32; > + v |= hvm_get_32u(h); > + > + return v; > +} > + > +static inline void hvm_get_buffer(hvm_domain_context_t *h, char *buf, int len) > +{ > + memcpy(buf, &h->data[h->cur], len); > + h->cur += len; > +} > + > +extern int hvm_save(struct vcpu*, hvm_domain_context_t *h); > +extern int hvm_load(struct vcpu*, hvm_domain_context_t *h); > + > +extern int arch_sethvm_ctxt(struct vcpu *v, struct hvm_domain_context *c); > +extern int arch_gethvm_ctxt(struct vcpu *v, struct hvm_domain_context *c); > + > extern int hvm_enabled; > > int hvm_copy_to_guest_phys(paddr_t paddr, void *buf, int size); > diff -r 7a38592d0cc9 xen/include/public/domctl.h > --- a/xen/include/public/domctl.h Tue Jan 09 15:33:30 2007 +0800 > +++ b/xen/include/public/domctl.h Tue Jan 09 15:37:58 2007 +0800 > @@ -386,6 +386,21 @@ struct xen_domctl_settimeoffset { > }; > typedef struct xen_domctl_settimeoffset xen_domctl_settimeoffset_t; > DEFINE_XEN_GUEST_HANDLE(xen_domctl_settimeoffset_t); > + > +#define HVM_CTXT_SIZE 6144 > +typedef struct hvm_domain_context { > + uint32_t cur; > + uint32_t size; > + uint8_t data[HVM_CTXT_SIZE]; > +} hvm_domain_context_t; > +DEFINE_XEN_GUEST_HANDLE(hvm_domain_context_t); > + > +#define XEN_DOMCTL_gethvmcontext 33 > +#define XEN_DOMCTL_sethvmcontext 34 > +typedef struct xen_domctl_hvmcontext { > + XEN_GUEST_HANDLE(hvm_domain_context_t) ctxt; /* IN/OUT */ > +} xen_domctl_hvmcontext_t; > +DEFINE_XEN_GUEST_HANDLE(xen_domctl_hvmcontext_t); > > #define XEN_DOMCTL_real_mode_area 26 > struct xen_domctl_real_mode_area { > @@ -423,6 +438,7 @@ struct xen_domctl { > struct xen_domctl_arch_setup arch_setup; > struct xen_domctl_settimeoffset settimeoffset; > struct xen_domctl_real_mode_area real_mode_area; > + struct xen_domctl_hvmcontext hvmcontext; > uint8_t pad[128]; > } u; > };_______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel
Zhai, Edwin
2007-Jan-12 16:05 UTC
[Xen-devel] Re: [PATCH 2/8] HVM save restore: new hyper-call
On Thu, Jan 11, 2007 at 11:29:49AM -0600, Anthony Liguori wrote:> Zhai, Edwin wrote: > >+ > >+/* set info to hvm guest for restore */ > >+int xc_domain_hvm_setcontext(int xc_handle, > >+ uint32_t domid, > >+ hvm_domain_context_t *hvm_ctxt) > >+{ > >+ int rc; > >+ DECLARE_DOMCTL; > >+ > >+ domctl.cmd = XEN_DOMCTL_sethvmcontext; > >+ domctl.domain = domid; > >+ set_xen_guest_handle(domctl.u.hvmcontext.ctxt, hvm_ctxt); > >+ > >+ if ( (rc = mlock(hvm_ctxt, sizeof(*hvm_ctxt))) != 0 ) > >+ return rc; > >+ > >+ rc = do_domctl(xc_handle, &domctl); > >+ > >+ safe_munlock(hvm_ctxt, sizeof(*hvm_ctxt)); > >+ > >+ return rc; > > } > > Perhaps these should be lock_pages instead of calling mlock() directly?yes, you are right. i forgot to refresh old patch when rebase. attached minor fix is okay. thanks,> > Regards, > > Anthony Liguori >-- best rgds, edwin _______________________________________________ Xen-devel mailing list Xen-devel@lists.xensource.com http://lists.xensource.com/xen-devel