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