[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] [HVM] Save/restore: clean up marshalling code



# HG changeset patch
# User Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
# Date 1170239230 0
# Node ID ffcd586dbaae1c1f81132f0d7c697d8699b292bd
# Parent  7d3bb465e938575dfa54f362b87337d3ee012f4b
[HVM] Save/restore: clean up marshalling code
- All entries are now defined as structs and saved/restored
  in self-contained operations.
- Save/restore operations are type-safe, to tie each entry's
  typecode to a particular struct and its length.
- Save/restore handlers are registered once per host instead of
  per domain.
- Detect buffer overrun before it happens and abort.

Signed-off-by: Tim Deegan <Tim.Deegan@xxxxxxxxxxxxx>
---
 xen/arch/x86/domctl.c             |    3 
 xen/arch/x86/hvm/hvm.c            |   71 +++---
 xen/arch/x86/hvm/i8254.c          |   25 +-
 xen/arch/x86/hvm/intercept.c      |  407 +++++++++++++-------------------------
 xen/arch/x86/hvm/svm/svm.c        |   33 ---
 xen/arch/x86/hvm/vioapic.c        |   70 +++---
 xen/arch/x86/hvm/vlapic.c         |  108 +++++++---
 xen/arch/x86/hvm/vmx/vmx.c        |   44 +---
 xen/arch/x86/hvm/vpic.c           |   51 +++-
 xen/include/asm-x86/hvm/domain.h  |   15 -
 xen/include/asm-x86/hvm/hvm.h     |    4 
 xen/include/asm-x86/hvm/support.h |  230 ++++++++++-----------
 xen/include/public/hvm/save.h     |   83 ++++++-
 13 files changed, 553 insertions(+), 591 deletions(-)

diff -r 7d3bb465e938 -r ffcd586dbaae xen/arch/x86/domctl.c
--- a/xen/arch/x86/domctl.c     Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/arch/x86/domctl.c     Wed Jan 31 10:27:10 2007 +0000
@@ -302,6 +302,8 @@ long arch_do_domctl(
         ret = -EFAULT;
         if ( copy_from_guest(c, domctl->u.hvmcontext.ctxt, 1) != 0 )
             goto sethvmcontext_out;
+        c->size = sizeof (c->data);
+        c->cur = 0;
 
         ret = -EINVAL;
         if ( !is_hvm_domain(d) ) 
@@ -330,6 +332,7 @@ long arch_do_domctl(
         if ( (c = xmalloc(struct hvm_domain_context)) == NULL )
             goto gethvmcontext_out;
         memset(c, 0, sizeof(*c));
+        c->size = sizeof (c->data);
         
         ret = -ENODATA;
         if ( !is_hvm_domain(d) ) 
diff -r 7d3bb465e938 -r ffcd586dbaae xen/arch/x86/hvm/hvm.c
--- a/xen/arch/x86/hvm/hvm.c    Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/arch/x86/hvm/hvm.c    Wed Jan 31 10:27:10 2007 +0000
@@ -168,19 +168,11 @@ 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);
@@ -189,23 +181,43 @@ void hvm_domain_destroy(struct domain *d
         unmap_domain_page_global((void *)d->arch.hvm_domain.buffered_io_va);
 }
 
-void hvm_save_cpu_ctxt(hvm_domain_context_t *h, void *opaque)
-{
-    struct vcpu *v = opaque;
-
-    /* We don't need to save state for a vcpu that is down; the restore 
-     * code will leave it down if there is nothing saved. */
-    if ( test_bit(_VCPUF_down, &v->vcpu_flags) ) 
-        return;
-
-    hvm_funcs.save_cpu_ctxt(h, opaque);
-}
-
-int hvm_load_cpu_ctxt(hvm_domain_context_t *h, void *opaque, int version)
-{
-    struct vcpu *v = opaque;
-
-    if ( hvm_funcs.load_cpu_ctxt(h, opaque, version) < 0 )
+static int hvm_save_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
+{
+    struct vcpu *v;
+    struct hvm_hw_cpu ctxt;
+
+    for_each_vcpu(d, v)
+    {
+        /* We don't need to save state for a vcpu that is down; the restore 
+         * code will leave it down if there is nothing saved. */
+        if ( test_bit(_VCPUF_down, &v->vcpu_flags) ) 
+            continue;
+
+        hvm_funcs.save_cpu_ctxt(v, &ctxt);
+        if ( hvm_save_entry(CPU, v->vcpu_id, h, &ctxt) != 0 )
+            return 1; 
+    }
+    return 0;
+}
+
+static int hvm_load_cpu_ctxt(struct domain *d, hvm_domain_context_t *h)
+{
+    int vcpuid;
+    struct vcpu *v;
+    struct hvm_hw_cpu ctxt;
+
+    /* Which vcpu is this? */
+    vcpuid = hvm_load_instance(h);
+    if ( vcpuid > MAX_VIRT_CPUS || (v = d->vcpu[vcpuid]) == NULL ) 
+    {
+        gdprintk(XENLOG_ERR, "HVM restore: domain has no vcpu %u\n", vcpuid);
+        return -EINVAL;
+    }
+
+    if ( hvm_load_entry(CPU, h, &ctxt) != 0 ) 
+        return -EINVAL;
+
+    if ( hvm_funcs.load_cpu_ctxt(v, &ctxt) < 0 )
         return -EINVAL;
 
     /* Auxiliary processors should be woken immediately. */
@@ -215,13 +227,11 @@ int hvm_load_cpu_ctxt(hvm_domain_context
     return 0;
 }
 
+HVM_REGISTER_SAVE_RESTORE(CPU, hvm_save_cpu_ctxt, hvm_load_cpu_ctxt);
+
 int hvm_vcpu_initialise(struct vcpu *v)
 {
     int rc;
-
-    hvm_register_savevm(v->domain, "xen_hvm_cpu", v->vcpu_id, 1,
-                        hvm_save_cpu_ctxt, hvm_load_cpu_ctxt, 
-                        (void *)v);
 
     if ( (rc = vlapic_init(v)) != 0 )
         return rc;
@@ -248,9 +258,6 @@ int hvm_vcpu_initialise(struct vcpu *v)
     pmtimer_init(v, ACPI_PM_TMR_BLK_ADDRESS);
     hpet_init(v);
  
-    /* init hvm sharepage */
-    shpage_init(v->domain, get_sp(v->domain));
-
     /* Init guest TSC to start from zero. */
     hvm_set_guest_time(v, 0);
 
diff -r 7d3bb465e938 -r ffcd586dbaae xen/arch/x86/hvm/i8254.c
--- a/xen/arch/x86/hvm/i8254.c  Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/arch/x86/hvm/i8254.c  Wed Jan 31 10:27:10 2007 +0000
@@ -411,28 +411,24 @@ static void pit_info(PITState *pit)
 }
 #endif
 
-static void pit_save(hvm_domain_context_t *h, void *opaque)
-{
-    struct domain *d = opaque;
+static int pit_save(struct domain *d, hvm_domain_context_t *h)
+{
     PITState *pit = &d->arch.hvm_domain.pl_time.vpit;
     
     pit_info(pit);
 
     /* Save the PIT hardware state */
-    hvm_put_struct(h, &pit->hw);
-}
-
-static int pit_load(hvm_domain_context_t *h, void *opaque, int version_id)
-{
-    struct domain *d = opaque;
+    return hvm_save_entry(PIT, 0, h, &pit->hw);
+}
+
+static int pit_load(struct domain *d, hvm_domain_context_t *h)
+{
     PITState *pit = &d->arch.hvm_domain.pl_time.vpit;
     int i;
 
-    if (version_id != 1)
-        return -EINVAL;
-
     /* Restore the PIT hardware state */
-    hvm_get_struct(h, &pit->hw);
+    if ( hvm_load_entry(PIT, h, &pit->hw) )
+        return 1;
     
     /* Recreate platform timers from hardware state.  There will be some 
      * time jitter here, but the wall-clock will have jumped massively, so 
@@ -446,6 +442,8 @@ static int pit_load(hvm_domain_context_t
     pit_info(pit);
     return 0;
 }
+
+HVM_REGISTER_SAVE_RESTORE(PIT, pit_save, pit_load);
 
 static void pit_reset(void *opaque)
 {
@@ -474,7 +472,6 @@ void pit_init(struct vcpu *v, unsigned l
     pt++; pt->vcpu = v;
     pt++; pt->vcpu = v;
 
-    hvm_register_savevm(v->domain, "xen_hvm_i8254", PIT_BASE, 1, pit_save, 
pit_load, v->domain);
     register_portio_handler(v->domain, PIT_BASE, 4, handle_pit_io);
     /* register the speaker port */
     register_portio_handler(v->domain, 0x61, 1, handle_speaker_io);
diff -r 7d3bb465e938 -r ffcd586dbaae xen/arch/x86/hvm/intercept.c
--- a/xen/arch/x86/hvm/intercept.c      Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/arch/x86/hvm/intercept.c      Wed Jan 31 10:27:10 2007 +0000
@@ -157,176 +157,129 @@ static inline void hvm_mmio_access(struc
     }
 }
 
-
-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;
-    }
-
-    safe_strcpy(se->idstr, idstr);
-
-    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;
-}
+/* List of handlers for various HVM save and restore types */
+static struct { 
+    hvm_save_handler save;
+    hvm_load_handler load; 
+} hvm_sr_handlers [HVM_SAVE_CODE_MAX + 1] = {{NULL, NULL},};
+
+/* Init-time function to add entries to that list */
+void hvm_register_savevm(uint16_t typecode, 
+                         hvm_save_handler save_state,
+                         hvm_load_handler load_state)
+{
+    ASSERT(typecode <= HVM_SAVE_CODE_MAX);
+    ASSERT(hvm_sr_handlers[typecode].save == NULL);
+    ASSERT(hvm_sr_handlers[typecode].load == NULL);
+    hvm_sr_handlers[typecode].save = save_state;
+    hvm_sr_handlers[typecode].load = load_state;
+}
+
 
 int hvm_save(struct domain *d, hvm_domain_context_t *h)
 {
-    uint32_t len, len_pos, cur_pos;
     uint32_t eax, ebx, ecx, edx;
-    HVMStateEntry *se;
-    char *chgset;
+    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 some CPUID bits */
     cpuid(1, &eax, &ebx, &ecx, &edx);
     hdr.cpuid = eax;
-    hvm_put_struct(h, &hdr);
-
-    /* save xen changeset */
-    chgset = strrchr(XEN_CHANGESET, ' ');
-    if ( chgset )
-        chgset++;
+
+    /* Save xen changeset */
+    c = strrchr(XEN_CHANGESET, ':');
+    if ( c )
+        hdr.changeset = simple_strtoll(c, NULL, 16);
+    else 
+        hdr.changeset = -1ULL; /* Unknown */
+
+    if ( hvm_save_entry(HEADER, 0, h, &hdr) != 0 )
+    {
+        gdprintk(XENLOG_ERR, "HVM save: failed to write header\n");
+        return -1;
+    } 
+
+    /* Save all available kinds of state */
+    for ( i = 0; i <= HVM_SAVE_CODE_MAX; i++ ) 
+    {
+        handler = hvm_sr_handlers[i].save;
+        if ( handler != NULL ) 
+        {
+            if ( handler(d, h) != 0 ) 
+            {
+                gdprintk(XENLOG_ERR, 
+                         "HVM save: failed to save type %"PRIu16"\n", i);
+                return -1;
+            } 
+        }
+    }
+
+    /* 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 -1;
+    }
+
+    /* Save macros should not have let us overrun */
+    ASSERT(h->cur <= h->size);
+    return 0;
+}
+
+int hvm_load(struct domain *d, hvm_domain_context_t *h)
+{
+    uint32_t eax, ebx, ecx, edx;
+    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 (hdr.magic != HVM_FILE_MAGIC) {
+        gdprintk(XENLOG_ERR, 
+                 "HVM restore: bad magic number %#"PRIx32"\n", hdr.magic);
+        return -1;
+    }
+
+    if (hdr.version != HVM_FILE_VERSION) {
+        gdprintk(XENLOG_ERR, 
+                 "HVM restore: unsupported version %u\n", hdr.version);
+        return -1;
+    }
+
+    cpuid(1, &eax, &ebx, &ecx, &edx);
+    /*TODO: need to define how big a difference is acceptable */
+    if (hdr.cpuid != eax)
+        gdprintk(XENLOG_WARNING, "HVM restore: saved CPUID (%#"PRIx32") "
+               "does not match host (%#"PRIx32").\n", hdr.cpuid, eax);
+
+
+    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
-        chgset = XEN_CHANGESET;
-
-    len = strlen(chgset);
-    hvm_put_8u(h, len);
-    hvm_put_buffer(h, chgset, len);
-
-    for(se = d->arch.hvm_domain.first_se; se != NULL; se = se->next) {
-        /* ID string */
-        len = strnlen(se->idstr, sizeof(se->idstr));
-        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, sizeof(se->idstr)) &&
-            instance_id == se->instance_id){
-            return se;
-        }
-    }
-    return NULL;
-}
-
-int hvm_load(struct domain *d, hvm_domain_context_t *h)
-{
-    uint32_t len, rec_len, rec_pos, 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;
-    struct hvm_save_header hdr;
-    struct vcpu *v;
-
-    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);
-
-    hvm_get_struct(h, &hdr);
-
-    if (hdr.magic != HVM_FILE_MAGIC) {
-        printk("HVM restore magic dismatch!\n");
-        return -1;
-    }
-
-    if (hdr.version != HVM_FILE_VERSION) {
-        printk("HVM restore version dismatch!\n");
-        return -1;
-    }
-
-    /* check cpuid */
-    cpuid(1, &eax, &ebx, &ecx, &edx);
-    /*TODO: need difine how big difference is acceptable */
-    if (hdr.cpuid != eax)
-        printk("warnings: try to restore hvm guest(0x%"PRIx32") "
-               "on a different type processor(0x%"PRIx32").\n",
-                hdr.cpuid,
-                eax);
-
-
-    /* check xen change set */
-    cur_chgset = strrchr(XEN_CHANGESET, ' ');
-    if ( cur_chgset )
-        cur_chgset++;
-    else
-        cur_chgset = XEN_CHANGESET;
-
-    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);
-
-
-    if ( !strcmp(cur_chgset, "unavailable") )
-        printk("warnings: try to restore hvm guest when changeset is 
unavailable.\n");
-
+    {
+        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) 
@@ -334,109 +287,43 @@ int hvm_load(struct domain *d, hvm_domai
             vcpu_sleep_nosync(v);
 
     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);
+
+        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;
         }
-
-        hvm_get_buffer(h, idstr, len);
-        idstr[len] = '\0';
-
-        instance_id = hvm_get_32u(h);
-        version_id = hvm_get_32u(h);
-
-        printk("HVM S/R Loading \"%s\" instance %#x\n", idstr, instance_id);
-
-        rec_len = hvm_get_32u(h);
-        rec_pos = hvm_ctxt_tell(h);
-
-        se = find_se(d, 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;
-}
-
-
-#ifdef HVM_DEBUG_SUSPEND
-static void shpage_info(shared_iopage_t *sh)
-{
-
-    vcpu_iodata_t *p = &sh->vcpu_iodata[0];
-    ioreq_t *req = &p->vp_ioreq;
-    printk("*****sharepage_info******!\n");
-    printk("vp_eport=%d\n", p->vp_eport);
-    printk("io packet: "
-                     "state:%x, pvalid: %x, dir:%x, port: %"PRIx64", "
-                     "data: %"PRIx64", count: %"PRIx64", size: %"PRIx64"\n",
-                     req->state, req->data_is_ptr, req->dir, req->addr,
-                     req->data, req->count, req->size);
-}
-#else
-static void shpage_info(shared_iopage_t *sh)
-{
-}
-#endif
-
-static void shpage_save(hvm_domain_context_t *h, void *opaque)
-{
-    /* XXX:no action required for shpage save/restore, since it's in guest 
memory
-     * keep it for debug purpose only */
-
-#if 0
-    struct shared_iopage *s = opaque;
-    /* XXX:smp */
-    struct ioreq *req = &s->vcpu_iodata[0].vp_ioreq;
-    
-    shpage_info(s);
-
-    hvm_put_buffer(h, (char*)req, sizeof(struct ioreq));
-#endif
-}
-
-static int shpage_load(hvm_domain_context_t *h, void *opaque, int version_id)
-{
-    struct shared_iopage *s = opaque;
-#if 0
-    /* XXX:smp */
-    struct ioreq *req = &s->vcpu_iodata[0].vp_ioreq;
-
-    if (version_id != 1)
-        return -EINVAL;
-
-    hvm_get_buffer(h, (char*)req, sizeof(struct ioreq));
-
-
-#endif
-    shpage_info(s);
-    return 0;
-}
-
-void shpage_init(struct domain *d, shared_iopage_t *sp)
-{
-    hvm_register_savevm(d, "xen_hvm_shpage", 0x10, 1, shpage_save, 
shpage_load, sp);
-}
+        
+        /* 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 */
+        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 */
+}
+
 
 int hvm_buffered_io_intercept(ioreq_t *p)
 {
diff -r 7d3bb465e938 -r ffcd586dbaae xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/arch/x86/hvm/svm/svm.c        Wed Jan 31 10:27:10 2007 +0000
@@ -603,29 +603,16 @@ void svm_load_cpu_state(struct vcpu *v, 
     // dump_msr_state(guest_state);
 }
 
-void svm_save_vmcb_ctxt(hvm_domain_context_t *h, void *opaque)
-{
-    struct vcpu *v = opaque;
-    struct hvm_hw_cpu ctxt;
-
-    svm_save_cpu_state(v, &ctxt);
-
-    svm_vmcs_save(v, &ctxt);
-
-    hvm_put_struct(h, &ctxt);
-}
-
-int svm_load_vmcb_ctxt(hvm_domain_context_t *h, void *opaque, int version)
-{
-    struct vcpu *v = opaque;
-    struct hvm_hw_cpu ctxt;
-
-    if (version != 1)
-        return -EINVAL;
-
-    hvm_get_struct(h, &ctxt);
-    svm_load_cpu_state(v, &ctxt);
-    if (svm_vmcb_restore(v, &ctxt)) {
+void svm_save_vmcb_ctxt(struct vcpu *v, struct hvm_hw_cpu *ctxt)
+{
+    svm_save_cpu_state(v, ctxt);
+    svm_vmcs_save(v, ctxt);
+}
+
+int svm_load_vmcb_ctxt(struct vcpu *v, struct hvm_hw_cpu *ctxt)
+{
+    svm_load_cpu_state(v, ctxt);
+    if (svm_vmcb_restore(v, ctxt)) {
         printk("svm_vmcb restore failed!\n");
         domain_crash(v->domain);
         return -EINVAL;
diff -r 7d3bb465e938 -r ffcd586dbaae xen/arch/x86/hvm/vioapic.c
--- a/xen/arch/x86/hvm/vioapic.c        Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/arch/x86/hvm/vioapic.c        Wed Jan 31 10:27:10 2007 +0000
@@ -523,49 +523,57 @@ static void hvmirq_info(struct hvm_hw_ir
 }
 #endif
 
-static void ioapic_save(hvm_domain_context_t *h, void *opaque)
-{
-    struct domain *d = opaque;
+
+static int ioapic_save(struct domain *d, hvm_domain_context_t *h)
+{
     struct hvm_hw_vioapic *s = domain_vioapic(d);
+    ioapic_info(s);
+
+    /* save io-apic state*/
+    return ( hvm_save_entry(IOAPIC, 0, h, s) );
+}
+
+static int ioapic_save_irqs(struct domain *d, hvm_domain_context_t *h)
+{
     struct hvm_hw_irq *hvm_irq = &d->arch.hvm_domain.irq;
+    hvmirq_info(hvm_irq);
+
+    /* save IRQ state*/
+    return ( hvm_save_entry(IRQ, 0, h, hvm_irq) );    
+}
+
+
+static int ioapic_load(struct domain *d, hvm_domain_context_t *h)
+{
+    struct hvm_hw_vioapic *s = domain_vioapic(d);
+    
+    /* restore ioapic state */
+    if ( hvm_load_entry(IOAPIC, h, s) != 0 )
+        return -EINVAL;
 
     ioapic_info(s);
+    return 0;
+}
+
+static int ioapic_load_irqs(struct domain *d, hvm_domain_context_t *h)
+{
+    struct hvm_hw_irq *hvm_irq = &d->arch.hvm_domain.irq;
+
+    /* restore irq state */
+    if ( hvm_load_entry(IRQ, h, hvm_irq) != 0 )
+        return -EINVAL;
+
     hvmirq_info(hvm_irq);
-
-    /* save io-apic state*/
-    hvm_put_struct(h, s);
-
-    /* save hvm irq state */
-    hvm_put_struct(h, hvm_irq);
-}
-
-static int ioapic_load(hvm_domain_context_t *h, void *opaque, int version_id)
-{
-    struct domain *d = opaque;
-    struct hvm_hw_vioapic *s = domain_vioapic(d);
-    struct hvm_hw_irq *hvm_irq = &d->arch.hvm_domain.irq;
-    
-    if (version_id != 1)
-        return -EINVAL;
-
-    /* restore ioapic state */
-    hvm_get_struct(h, s);
-
-    /* restore irq state */
-    hvm_get_struct(h, hvm_irq);
-
-    ioapic_info(s);
-    hvmirq_info(hvm_irq);
-
     return 0;
 }
+
+HVM_REGISTER_SAVE_RESTORE(IOAPIC, ioapic_save, ioapic_load);
+HVM_REGISTER_SAVE_RESTORE(IRQ, ioapic_save_irqs, ioapic_load_irqs);
 
 void vioapic_init(struct domain *d)
 {
     struct hvm_hw_vioapic *vioapic = domain_vioapic(d);
     int i;
-
-    hvm_register_savevm(d, "xen_hvm_ioapic", 0, 1, ioapic_save, ioapic_load, 
d);
 
     memset(vioapic, 0, sizeof(*vioapic));
     for ( i = 0; i < VIOAPIC_NUM_PINS; i++ )
diff -r 7d3bb465e938 -r ffcd586dbaae xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/arch/x86/hvm/vlapic.c Wed Jan 31 10:27:10 2007 +0000
@@ -810,50 +810,105 @@ static void lapic_info(struct vlapic *s)
 }
 #endif
 
-static void lapic_save(hvm_domain_context_t *h, void *opaque)
-{
-    struct vlapic *s = opaque;
-
-    lapic_info(s);
-
-    hvm_put_struct(h, &s->hw);
-    hvm_put_struct(h, s->regs);
-}
-
-static int lapic_load(hvm_domain_context_t *h, void *opaque, int version_id)
-{
-    struct vlapic *s = opaque;
-    struct vcpu *v = vlapic_vcpu(s);
+/* rearm the actimer if needed, after a HVM restore */
+static void lapic_rearm(struct vlapic *s)
+{
     unsigned long tmict;
 
-    if (version_id != 1)
-        return -EINVAL;
-
-    hvm_get_struct(h, &s->hw);
-    hvm_get_struct(h, s->regs);
-
-    /* rearm the actiemr if needed */
     tmict = vlapic_get_reg(s, APIC_TMICT);
     if (tmict > 0) {
         uint64_t period = APIC_BUS_CYCLE_NS * (uint32_t)tmict * 
s->hw.timer_divisor;
         uint32_t lvtt = vlapic_get_reg(s, APIC_LVTT);
 
         s->pt.irq = lvtt & APIC_VECTOR_MASK;
-        create_periodic_time(v, &s->pt, period, s->pt.irq,
+        create_periodic_time(vlapic_vcpu(s), &s->pt, period, s->pt.irq,
                              vlapic_lvtt_period(s), NULL, s);
 
         printk("lapic_load to rearm the actimer:"
                     "bus cycle is %uns, "
                     "saved tmict count %lu, period %"PRIu64"ns, 
irq=%"PRIu8"\n",
                     APIC_BUS_CYCLE_NS, tmict, period, s->pt.irq);
-
-    }
-
+    }
 
     lapic_info(s);
-
+}
+
+static int lapic_save_hidden(struct domain *d, hvm_domain_context_t *h)
+{
+    struct vcpu *v;
+    struct vlapic *s;
+
+    for_each_vcpu(d, v)
+    {
+        s = vcpu_vlapic(v);
+        lapic_info(s);
+
+        if ( hvm_save_entry(LAPIC, v->vcpu_id, h, &s->hw) != 0 )
+            return 1; 
+    }
     return 0;
 }
+
+static int lapic_save_regs(struct domain *d, hvm_domain_context_t *h)
+{
+    struct vcpu *v;
+    struct vlapic *s;
+
+    for_each_vcpu(d, v)
+    {
+        s = vcpu_vlapic(v);
+        if ( hvm_save_entry(LAPIC_REGS, v->vcpu_id, h, s->regs) != 0 )
+            return 1; 
+    }
+    return 0;
+}
+
+static int lapic_load_hidden(struct domain *d, hvm_domain_context_t *h)
+{
+    uint16_t vcpuid;
+    struct vcpu *v;
+    struct vlapic *s;
+    
+    /* Which vlapic to load? */
+    vcpuid = hvm_load_instance(h); 
+    if ( vcpuid > MAX_VIRT_CPUS || (v = d->vcpu[vcpuid]) == NULL ) 
+    {
+        gdprintk(XENLOG_ERR, "HVM restore: domain has no vlapic %u\n", vcpuid);
+        return -EINVAL;
+    }
+    s = vcpu_vlapic(v);
+    
+    if ( hvm_load_entry(LAPIC, h, &s->hw) != 0 ) 
+        return -EINVAL;
+
+    lapic_info(s);
+    return 0;
+}
+
+static int lapic_load_regs(struct domain *d, hvm_domain_context_t *h)
+{
+    uint16_t vcpuid;
+    struct vcpu *v;
+    struct vlapic *s;
+    
+    /* Which vlapic to load? */
+    vcpuid = hvm_load_instance(h); 
+    if ( vcpuid > MAX_VIRT_CPUS || (v = d->vcpu[vcpuid]) == NULL ) 
+    {
+        gdprintk(XENLOG_ERR, "HVM restore: domain has no vlapic %u\n", vcpuid);
+        return -EINVAL;
+    }
+    s = vcpu_vlapic(v);
+    
+    if ( hvm_load_entry(LAPIC_REGS, h, s->regs) != 0 ) 
+        return -EINVAL;
+
+    lapic_rearm(s);
+    return 0;
+}
+
+HVM_REGISTER_SAVE_RESTORE(LAPIC, lapic_save_hidden, lapic_load_hidden);
+HVM_REGISTER_SAVE_RESTORE(LAPIC_REGS, lapic_save_regs, lapic_load_regs);
 
 int vlapic_init(struct vcpu *v)
 {
@@ -873,7 +928,6 @@ int vlapic_init(struct vcpu *v)
     vlapic->regs = map_domain_page_global(page_to_mfn(vlapic->regs_page));
     memset(vlapic->regs, 0, PAGE_SIZE);
 
-    hvm_register_savevm(v->domain, "xen_hvm_lapic", v->vcpu_id, 1, lapic_save, 
lapic_load, vlapic);
     vlapic_reset(vlapic);
 
     vlapic->hw.apic_base_msr = MSR_IA32_APICBASE_ENABLE | 
APIC_DEFAULT_PHYS_BASE;
diff -r 7d3bb465e938 -r ffcd586dbaae xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Wed Jan 31 10:27:10 2007 +0000
@@ -364,19 +364,9 @@ static inline void __restore_debug_regis
     /* DR7 is loaded from the VMCS. */
 }
 
-static int __get_instruction_length(void);
 int vmx_vmcs_save(struct vcpu *v, struct hvm_hw_cpu *c)
-{
-    unsigned long inst_len;
-
-    inst_len = __get_instruction_length();
+{    
     c->eip = __vmread(GUEST_RIP);
-
-#ifdef HVM_DEBUG_SUSPEND
-    printk("vmx_vmcs_save: inst_len=0x%lx, eip=0x%"PRIx64".\n", 
-            inst_len, c->eip);
-#endif
-
     c->esp = __vmread(GUEST_RSP);
     c->eflags = __vmread(GUEST_RFLAGS);
 
@@ -632,30 +622,18 @@ void vmx_load_cpu_state(struct vcpu *v, 
 }
 
 
-void vmx_save_vmcs_ctxt(hvm_domain_context_t *h, void *opaque)
-{
-    struct vcpu *v = opaque;
-    struct hvm_hw_cpu ctxt;
-
-    vmx_save_cpu_state(v, &ctxt);
+void vmx_save_vmcs_ctxt(struct vcpu *v, struct hvm_hw_cpu *ctxt)
+{
+    vmx_save_cpu_state(v, ctxt);
     vmx_vmcs_enter(v);
-    vmx_vmcs_save(v, &ctxt);
+    vmx_vmcs_save(v, ctxt);
     vmx_vmcs_exit(v);
-
-    hvm_put_struct(h, &ctxt);
-}
-
-int vmx_load_vmcs_ctxt(hvm_domain_context_t *h, void *opaque, int version)
-{
-    struct vcpu *v = opaque;
-    struct hvm_hw_cpu ctxt;
-
-    if (version != 1)
-        return -EINVAL;
-
-    hvm_get_struct(h, &ctxt);
-    vmx_load_cpu_state(v, &ctxt);
-    if (vmx_vmcs_restore(v, &ctxt)) {
+}
+
+int vmx_load_vmcs_ctxt(struct vcpu *v, struct hvm_hw_cpu *ctxt)
+{
+    vmx_load_cpu_state(v, ctxt);
+    if (vmx_vmcs_restore(v, ctxt)) {
         printk("vmx_vmcs restore failed!\n");
         domain_crash(v->domain);
         return -EINVAL;
diff -r 7d3bb465e938 -r ffcd586dbaae xen/arch/x86/hvm/vpic.c
--- a/xen/arch/x86/hvm/vpic.c   Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/arch/x86/hvm/vpic.c   Wed Jan 31 10:27:10 2007 +0000
@@ -404,26 +404,43 @@ static void vpic_info(struct hvm_hw_vpic
 }
 #endif
 
-static void vpic_save(hvm_domain_context_t *h, void *opaque)
-{
-    struct hvm_hw_vpic *s = opaque;
+static int vpic_save(struct domain *d, hvm_domain_context_t *h)
+{
+    struct hvm_hw_vpic *s;
+    int i;
+
+    /* Save the state of both PICs */
+    for ( i = 0; i < 2 ; i++ )
+    {
+        s = &d->arch.hvm_domain.vpic[i];
+        vpic_info(s);
+        if ( hvm_save_entry(PIC, i, h, s) )
+            return 1;
+    }
+
+    return 0;
+}
+
+static int vpic_load(struct domain *d, hvm_domain_context_t *h)
+{
+    struct hvm_hw_vpic *s;
+    uint16_t inst;
     
+    /* Which PIC is this? */
+    inst = hvm_load_instance(h);
+    if ( inst > 1 )
+        return -EINVAL;
+    s = &d->arch.hvm_domain.vpic[inst];
+
+    /* Load the state */
+    if ( hvm_load_entry(PIC, h, s) != 0 )
+        return -EINVAL;
+
     vpic_info(s);
-    hvm_put_struct(h, s);
-}
-
-static int vpic_load(hvm_domain_context_t *h, void *opaque, int version_id)
-{
-    struct hvm_hw_vpic *s = opaque;
-    
-    if (version_id != 1)
-        return -EINVAL;
-
-    hvm_get_struct(h, s);
-    vpic_info(s);
-
     return 0;
 }
+
+HVM_REGISTER_SAVE_RESTORE(PIC, vpic_save, vpic_load);
 
 void vpic_init(struct domain *d)
 {
@@ -434,14 +451,12 @@ void vpic_init(struct domain *d)
     memset(vpic, 0, sizeof(*vpic));
     vpic->is_master = 1;
     vpic->elcr      = 1 << 2;
-    hvm_register_savevm(d, "xen_hvm_i8259", 0x20, 1, vpic_save, vpic_load, 
vpic);
     register_portio_handler(d, 0x20, 2, vpic_intercept_pic_io);
     register_portio_handler(d, 0x4d0, 1, vpic_intercept_elcr_io);
 
     /* Slave PIC. */
     vpic++;
     memset(vpic, 0, sizeof(*vpic));
-    hvm_register_savevm(d, "xen_hvm_i8259", 0xa0, 1, vpic_save, vpic_load, 
vpic);
     register_portio_handler(d, 0xa0, 2, vpic_intercept_pic_io);
     register_portio_handler(d, 0x4d1, 1, vpic_intercept_elcr_io);
 }
diff -r 7d3bb465e938 -r ffcd586dbaae xen/include/asm-x86/hvm/domain.h
--- a/xen/include/asm-x86/hvm/domain.h  Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/include/asm-x86/hvm/domain.h  Wed Jan 31 10:27:10 2007 +0000
@@ -28,20 +28,6 @@
 #include <public/hvm/params.h>
 #include <public/hvm/save.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;
@@ -65,7 +51,6 @@ struct hvm_domain {
     uint64_t               params[HVM_NR_PARAMS];
 
     struct hvm_domain_context *hvm_ctxt;
-    HVMStateEntry *first_se;
 };
 
 #endif /* __ASM_X86_HVM_DOMAIN_H__ */
diff -r 7d3bb465e938 -r ffcd586dbaae xen/include/asm-x86/hvm/hvm.h
--- a/xen/include/asm-x86/hvm/hvm.h     Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/include/asm-x86/hvm/hvm.h     Wed Jan 31 10:27:10 2007 +0000
@@ -83,8 +83,8 @@ struct hvm_function_table {
         struct vcpu *v, struct cpu_user_regs *r);
 
     /* save and load hvm guest cpu context for save/restore */
-    void (*save_cpu_ctxt)(hvm_domain_context_t *h, void *opaque);
-    int (*load_cpu_ctxt)(hvm_domain_context_t *h, void *opaque, int version);
+    void (*save_cpu_ctxt)(struct vcpu *v, struct hvm_hw_cpu *ctxt);
+    int (*load_cpu_ctxt)(struct vcpu *v, struct hvm_hw_cpu *ctxt);
 
     /*
      * Examine specifics of the guest state:
diff -r 7d3bb465e938 -r ffcd586dbaae xen/include/asm-x86/hvm/support.h
--- a/xen/include/asm-x86/hvm/support.h Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/include/asm-x86/hvm/support.h Wed Jan 31 10:27:10 2007 +0000
@@ -119,133 +119,121 @@ 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;
+/*
+ * Save/restore support 
+ */
+
+/* Marshalling an entry: check space and fill in the header */
+static inline int _hvm_init_entry(struct hvm_domain_context *h,
+                                  uint16_t tc, uint16_t inst, uint32_t len)
+{
+    struct hvm_save_descriptor *d 
+        = (struct hvm_save_descriptor *)&h->data[h->cur];
+    if ( h->size - h->cur < len + sizeof (*d) )
+    {
+        gdprintk(XENLOG_WARNING,
+                 "HVM save: no room for %"PRIu32" + %u bytes "
+                 "for typecode %"PRIu16"\n",
+                 len, (unsigned) sizeof (*d), tc);
+        return -1;
     }
-    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");
+    d->typecode = tc;
+    d->instance = inst;
+    d->length = len;
+    h->cur += sizeof (*d);
+    return 0;
+}
+
+/* Marshalling: copy the contents in a type-safe way */
+#define _hvm_write_entry(_x, _h, _src) do {                     \
+    *(HVM_SAVE_TYPE(_x) *)(&(_h)->data[(_h)->cur]) = *(_src);   \
+    (_h)->cur += HVM_SAVE_LENGTH(_x);                           \
+} while (0)
+
+/* Marshalling: init and copy; evaluates to zero on success */
+#define hvm_save_entry(_x, _inst, _h, _src) ({          \
+    int r;                                              \
+    r = _hvm_init_entry((_h), HVM_SAVE_CODE(_x),        \
+                        (_inst), HVM_SAVE_LENGTH(_x));  \
+    if ( r == 0 )                                       \
+        _hvm_write_entry(_x, (_h), (_src));             \
+    r; })
+
+/* Unmarshalling: test an entry's size and typecode and record the instance */
+static inline int _hvm_check_entry(struct hvm_domain_context *h, 
+                                   uint16_t type, uint32_t len)
+{
+    struct hvm_save_descriptor *d 
+        = (struct hvm_save_descriptor *)&h->data[h->cur];
+    if ( len + sizeof (*d) > h->size - h->cur)
+    {
+        gdprintk(XENLOG_WARNING, 
+                 "HVM restore: not enough data left to read %u bytes "
+                 "for type %u\n", len, type);
+        return -1;
+    }    
+    if ( type != d->typecode || len != d->length )
+    {
+        gdprintk(XENLOG_WARNING, 
+                 "HVM restore mismatch: expected type %u length %u, "
+                 "saw type %u length %u\n", type, len, d->typecode, d->length);
         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;
-}
-
-#define hvm_put_struct(_h, _p) \
-    hvm_put_buffer((_h), (char *)(_p), sizeof(*(_p)))
-#define hvm_get_struct(_h, _p) \
-    hvm_get_buffer((_h), (char *)(_p), sizeof(*(_p)))
-
+    h->cur += sizeof (*d);
+    return 0;
+}
+
+/* Unmarshalling: copy the contents in a type-safe way */
+#define _hvm_read_entry(_x, _h, _dst) do {                      \
+    *(_dst) = *(HVM_SAVE_TYPE(_x) *) (&(_h)->data[(_h)->cur]);  \
+    (_h)->cur += HVM_SAVE_LENGTH(_x);                           \
+} while (0)
+
+/* Unmarshalling: check, then copy. Evaluates to zero on success. */
+#define hvm_load_entry(_x, _h, _dst) ({                                 \
+    int r;                                                              \
+    r = _hvm_check_entry((_h), HVM_SAVE_CODE(_x), HVM_SAVE_LENGTH(_x)); \
+    if ( r == 0 )                                                       \
+        _hvm_read_entry(_x, (_h), (_dst));                              \
+    r; })
+
+/* Unmarshalling: what is the instance ID of the next entry? */
+static inline uint16_t hvm_load_instance(struct hvm_domain_context *h)
+{
+    struct hvm_save_descriptor *d 
+        = (struct hvm_save_descriptor *)&h->data[h->cur];
+    return d->instance;
+}
+
+/* Handler types for different types of save-file entry. 
+ * The save handler may save multiple instances of a type into the buffer;
+ * the load handler will be called once for each instance found when
+ * restoring.  Both return non-zero on error. */
+typedef int (*hvm_save_handler) (struct domain *d, 
+                                 hvm_domain_context_t *h);
+typedef int (*hvm_load_handler) (struct domain *d,
+                                 hvm_domain_context_t *h);
+
+/* Init-time function to declare a pair of handlers for a type */
+void hvm_register_savevm(uint16_t typecode, 
+                         hvm_save_handler save_state,
+                         hvm_load_handler load_state);
+
+/* Syntactic sugar around that function */
+#define HVM_REGISTER_SAVE_RESTORE(_x, _save, _load)             \
+static int __hvm_register_##_x##_save_and_restore(void)         \
+{                                                               \
+    hvm_register_savevm(HVM_SAVE_CODE(_x), &_save, &_load);     \
+    return 0;                                                   \
+}                                                               \
+__initcall(__hvm_register_##_x##_save_and_restore);
+
+
+/* Entry points for saving and restoring HVM domain state */
 int hvm_save(struct domain *d, hvm_domain_context_t *h);
 int hvm_load(struct domain *d, hvm_domain_context_t *h);
 
-void shpage_init(struct domain *d, shared_iopage_t *sp);
+/* End of save/restore */
 
 extern char hvm_io_bitmap[];
 extern int hvm_enabled;
diff -r 7d3bb465e938 -r ffcd586dbaae xen/include/public/hvm/save.h
--- a/xen/include/public/hvm/save.h     Wed Jan 31 10:11:26 2007 +0000
+++ b/xen/include/public/hvm/save.h     Wed Jan 31 10:27:10 2007 +0000
@@ -40,24 +40,52 @@
  */
 
 /* 
- * Save/restore header
- */
-
-#define HVM_SAVE_TYPE_HEADER 0
+ * Each entry is preceded by a descriptor giving its type and length
+ */
+struct hvm_save_descriptor {
+    uint16_t typecode;          /* Used to demux the various types below */
+    uint16_t instance;          /* Further demux within a type */
+    uint32_t length;            /* In bytes, *not* including this descriptor */
+};
+
+
+/* 
+ * Each entry has a datatype associated with it: for example, the CPU state 
+ * is saved as a HVM_SAVE_TYPE(CPU), which has HVM_SAVE_LENGTH(CPU), 
+ * and is identified by a descriptor with typecode HVM_SAVE_CODE(CPU).
+ * DECLARE_HVM_SAVE_TYPE binds these things together with some type-system
+ * ugliness.
+ */
+
+#define DECLARE_HVM_SAVE_TYPE(_x, _code, _type)                   \
+  struct __HVM_SAVE_TYPE_##_x { _type t; char c[_code]; }
+
+#define HVM_SAVE_TYPE(_x) typeof (((struct __HVM_SAVE_TYPE_##_x *)(0))->t)
+#define HVM_SAVE_LENGTH(_x) (sizeof (HVM_SAVE_TYPE(_x)))
+#define HVM_SAVE_CODE(_x) (sizeof (((struct __HVM_SAVE_TYPE_##_x *)(0))->c))
+
+
+/* 
+ * Save/restore header: general info about the save file. 
+ */
 
 #define HVM_FILE_MAGIC   0x54381286
 #define HVM_FILE_VERSION 0x00000001
 
 struct hvm_save_header {
-    uint32_t magic;
-    uint32_t version;
-    uint32_t cpuid;
-};
+    uint32_t magic;             /* Must be HVM_FILE_MAGIC */
+    uint32_t version;           /* File format version */
+    uint64_t changeset;         /* Version of Xen that saved this file */
+    uint32_t cpuid;             /* CPUID[0x01][%eax] on the saving machine */
+};
+
+DECLARE_HVM_SAVE_TYPE(HEADER, 1, struct hvm_save_header);
+
 
 /*
  * Processor
  */
-#define HVM_SAVE_TYPE_CPU  1
+
 struct hvm_hw_cpu {
     uint64_t eip;
     uint64_t esp;
@@ -124,11 +152,13 @@ struct hvm_hw_cpu {
     uint64_t tsc;
 };
 
+DECLARE_HVM_SAVE_TYPE(CPU, 2, struct hvm_hw_cpu);
+
 
 /* 
  *  PIT
  */
-#define HVM_SAVE_TYPE_PIT 2
+
 struct hvm_hw_pit {
     struct hvm_hw_pit_channel {
         int64_t count_load_time;
@@ -148,11 +178,13 @@ struct hvm_hw_pit {
     uint32_t speaker_data_on;
 };
 
+DECLARE_HVM_SAVE_TYPE(PIT, 3, struct hvm_hw_pit);
+
 
 /*
  * PIC
  */
-#define HVM_SAVE_TYPE_PIC 3
+
 struct hvm_hw_vpic {
     /* IR line bitmasks. */
     uint8_t irr;
@@ -201,11 +233,12 @@ struct hvm_hw_vpic {
     uint8_t int_output;
 };
 
+DECLARE_HVM_SAVE_TYPE(PIC, 4, struct hvm_hw_vpic);
+
 
 /*
  * IO-APIC
  */
-#define HVM_SAVE_TYPE_IOAPIC 4
 
 #ifdef __ia64__
 #define VIOAPIC_IS_IOSAPIC 1
@@ -242,11 +275,13 @@ struct hvm_hw_vioapic {
     } redirtbl[VIOAPIC_NUM_PINS];
 };
 
+DECLARE_HVM_SAVE_TYPE(IOAPIC, 5, struct hvm_hw_vioapic);
+
 
 /*
  * IRQ
  */
-#define HVM_SAVE_TYPE_IRQ 5
+
 struct hvm_hw_irq {
     /*
      * Virtual interrupt wires for a single PCI bus.
@@ -309,22 +344,40 @@ struct hvm_hw_irq {
     u8 round_robin_prev_vcpu;
 };
 
+DECLARE_HVM_SAVE_TYPE(IRQ, 6, struct hvm_hw_irq);
 
 /*
  * LAPIC
  */
-#define HVM_SAVE_TYPE_LAPIC 6
+
 struct hvm_hw_lapic {
     uint64_t             apic_base_msr;
     uint32_t             disabled; /* VLAPIC_xx_DISABLED */
     uint32_t             timer_divisor;
 };
 
-#define HVM_SAVE_TYPE_LAPIC_REGS 7
+DECLARE_HVM_SAVE_TYPE(LAPIC, 7, struct hvm_hw_lapic);
 
 struct hvm_hw_lapic_regs {
     /* A 4k page of register state */
     uint8_t  data[0x400];
 };
 
+DECLARE_HVM_SAVE_TYPE(LAPIC_REGS, 8, struct hvm_hw_lapic_regs);
+
+
+/* 
+ * Largest type-code in use
+ */
+#define HVM_SAVE_CODE_MAX 8
+
+
+/* 
+ * The series of save records is teminated by a zero-type, zero-length 
+ * descriptor.
+ */
+
+struct hvm_save_end {};
+DECLARE_HVM_SAVE_TYPE(END, 0, struct hvm_save_end);
+
 #endif /* __XEN_PUBLIC_HVM_SAVE_H__ */

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.