ia64/xen-unstable

changeset 14208:139794d55898

Save/restore context of all online VCPUs in PV save/restore/migrate.
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Thu Mar 01 17:59:17 2007 +0000 (2007-03-01)
parents 33d733c3649d
children d12432f31311
files tools/libxc/xc_linux_restore.c tools/libxc/xc_linux_save.c
line diff
     1.1 --- a/tools/libxc/xc_linux_restore.c	Thu Mar 01 17:28:31 2007 +0000
     1.2 +++ b/tools/libxc/xc_linux_restore.c	Thu Mar 01 17:59:17 2007 +0000
     1.3 @@ -144,7 +144,7 @@ int xc_linux_restore(int xc_handle, int 
     1.4                       unsigned int console_evtchn, unsigned long *console_mfn)
     1.5  {
     1.6      DECLARE_DOMCTL;
     1.7 -    int rc = 1, i, n, m, pae_extended_cr3 = 0;
     1.8 +    int rc = 1, i, j, n, m, pae_extended_cr3 = 0;
     1.9      unsigned long mfn, pfn;
    1.10      unsigned int prev_pc, this_pc;
    1.11      int verify = 0;
    1.12 @@ -187,6 +187,8 @@ int xc_linux_restore(int xc_handle, int 
    1.13      struct mmuext_op pin[MAX_PIN_BATCH];
    1.14      unsigned int nr_pins;
    1.15  
    1.16 +    uint64_t vcpumap = 1ULL;
    1.17 +    unsigned int max_vcpu_id = 0;
    1.18  
    1.19      max_pfn = nr_pfns;
    1.20  
    1.21 @@ -369,6 +371,16 @@ int xc_linux_restore(int xc_handle, int 
    1.22              continue;
    1.23          }
    1.24  
    1.25 +        if (j == -2) {
    1.26 +            if (!read_exact(io_fd, &max_vcpu_id, sizeof(int)) ||
    1.27 +                (max_vcpu_id >= 64) ||
    1.28 +                !read_exact(io_fd, &vcpumap, sizeof(uint64_t))) {
    1.29 +                ERROR("Error when reading max_vcpu_id");
    1.30 +                goto out;
    1.31 +            }
    1.32 +            continue;
    1.33 +        }
    1.34 +
    1.35          if (j == 0)
    1.36              break;  /* our work here is done */
    1.37  
    1.38 @@ -776,64 +788,90 @@ int xc_linux_restore(int xc_handle, int 
    1.39          }
    1.40      }
    1.41  
    1.42 -    if (!read_exact(io_fd, &ctxt, sizeof(ctxt)) ||
    1.43 -        !read_exact(io_fd, shared_info_page, PAGE_SIZE)) {
    1.44 -        ERROR("Error when reading ctxt or shared info page");
    1.45 -        goto out;
    1.46 +    for (i = 0; i <= max_vcpu_id; i++) {
    1.47 +        if (!(vcpumap & (1ULL << i)))
    1.48 +            continue;
    1.49 +
    1.50 +        if (!read_exact(io_fd, &ctxt, sizeof(ctxt))) {
    1.51 +            ERROR("Error when reading ctxt %d", i);
    1.52 +            goto out;
    1.53 +        }
    1.54 +
    1.55 +        if (i == 0) {
    1.56 +            /*
    1.57 +             * Uncanonicalise the suspend-record frame number and poke
    1.58 +             * resume record.
    1.59 +             */
    1.60 +            pfn = ctxt.user_regs.edx;
    1.61 +            if ((pfn >= max_pfn) ||
    1.62 +                (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
    1.63 +                ERROR("Suspend record frame number is bad");
    1.64 +                goto out;
    1.65 +            }
    1.66 +            ctxt.user_regs.edx = mfn = p2m[pfn];
    1.67 +            start_info = xc_map_foreign_range(
    1.68 +                xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
    1.69 +            start_info->nr_pages = max_pfn;
    1.70 +            start_info->shared_info = shared_info_frame << PAGE_SHIFT;
    1.71 +            start_info->flags = 0;
    1.72 +            *store_mfn = start_info->store_mfn = p2m[start_info->store_mfn];
    1.73 +            start_info->store_evtchn = store_evtchn;
    1.74 +            start_info->console.domU.mfn = p2m[start_info->console.domU.mfn];
    1.75 +            start_info->console.domU.evtchn = console_evtchn;
    1.76 +            *console_mfn = start_info->console.domU.mfn;
    1.77 +            munmap(start_info, PAGE_SIZE);
    1.78 +        }
    1.79 +
    1.80 +        /* Uncanonicalise each GDT frame number. */
    1.81 +        if (ctxt.gdt_ents > 8192) {
    1.82 +            ERROR("GDT entry count out of range");
    1.83 +            goto out;
    1.84 +        }
    1.85 +
    1.86 +        for (j = 0; (512*j) < ctxt.gdt_ents; j++) {
    1.87 +            pfn = ctxt.gdt_frames[j];
    1.88 +            if ((pfn >= max_pfn) ||
    1.89 +                (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
    1.90 +                ERROR("GDT frame number is bad");
    1.91 +                goto out;
    1.92 +            }
    1.93 +            ctxt.gdt_frames[j] = p2m[pfn];
    1.94 +        }
    1.95 +
    1.96 +        /* Uncanonicalise the page table base pointer. */
    1.97 +        pfn = xen_cr3_to_pfn(ctxt.ctrlreg[3]);
    1.98 +
    1.99 +        if (pfn >= max_pfn) {
   1.100 +            ERROR("PT base is bad: pfn=%lu max_pfn=%lu type=%08lx",
   1.101 +                  pfn, max_pfn, pfn_type[pfn]);
   1.102 +            goto out;
   1.103 +        }
   1.104 +
   1.105 +        if ( (pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) !=
   1.106 +             ((unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT) ) {
   1.107 +            ERROR("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx",
   1.108 +                  pfn, max_pfn, pfn_type[pfn],
   1.109 +                  (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
   1.110 +            goto out;
   1.111 +        }
   1.112 +
   1.113 +        ctxt.ctrlreg[3] = xen_pfn_to_cr3(p2m[pfn]);
   1.114 +
   1.115 +        domctl.cmd = XEN_DOMCTL_setvcpucontext;
   1.116 +        domctl.domain = (domid_t)dom;
   1.117 +        domctl.u.vcpucontext.vcpu = i;
   1.118 +        set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt);
   1.119 +        rc = xc_domctl(xc_handle, &domctl);
   1.120 +        if (rc != 0) {
   1.121 +            ERROR("Couldn't build vcpu%d", i);
   1.122 +            goto out;
   1.123 +        }
   1.124      }
   1.125  
   1.126 -    /* Uncanonicalise the suspend-record frame number and poke resume rec. */
   1.127 -    pfn = ctxt.user_regs.edx;
   1.128 -    if ((pfn >= max_pfn) || (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
   1.129 -        ERROR("Suspend record frame number is bad");
   1.130 +    if (!read_exact(io_fd, shared_info_page, PAGE_SIZE)) {
   1.131 +        ERROR("Error when reading shared info page");
   1.132          goto out;
   1.133      }
   1.134 -    ctxt.user_regs.edx = mfn = p2m[pfn];
   1.135 -    start_info = xc_map_foreign_range(
   1.136 -        xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
   1.137 -    start_info->nr_pages    = max_pfn;
   1.138 -    start_info->shared_info = shared_info_frame << PAGE_SHIFT;
   1.139 -    start_info->flags       = 0;
   1.140 -    *store_mfn = start_info->store_mfn       = p2m[start_info->store_mfn];
   1.141 -    start_info->store_evtchn                 = store_evtchn;
   1.142 -    start_info->console.domU.mfn    = p2m[start_info->console.domU.mfn];
   1.143 -    start_info->console.domU.evtchn = console_evtchn;
   1.144 -    *console_mfn                    = start_info->console.domU.mfn;
   1.145 -    munmap(start_info, PAGE_SIZE);
   1.146 -
   1.147 -    /* Uncanonicalise each GDT frame number. */
   1.148 -    if (ctxt.gdt_ents > 8192) {
   1.149 -        ERROR("GDT entry count out of range");
   1.150 -        goto out;
   1.151 -    }
   1.152 -
   1.153 -    for (i = 0; (512*i) < ctxt.gdt_ents; i++) {
   1.154 -        pfn = ctxt.gdt_frames[i];
   1.155 -        if ((pfn >= max_pfn) || (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB)) {
   1.156 -            ERROR("GDT frame number is bad");
   1.157 -            goto out;
   1.158 -        }
   1.159 -        ctxt.gdt_frames[i] = p2m[pfn];
   1.160 -    }
   1.161 -
   1.162 -    /* Uncanonicalise the page table base pointer. */
   1.163 -    pfn = xen_cr3_to_pfn(ctxt.ctrlreg[3]);
   1.164 -
   1.165 -    if (pfn >= max_pfn) {
   1.166 -        ERROR("PT base is bad: pfn=%lu max_pfn=%lu type=%08lx",
   1.167 -            pfn, max_pfn, pfn_type[pfn]);
   1.168 -        goto out;
   1.169 -    }
   1.170 -
   1.171 -    if ( (pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) !=
   1.172 -         ((unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT) ) {
   1.173 -        ERROR("PT base is bad. pfn=%lu nr=%lu type=%08lx %08lx",
   1.174 -            pfn, max_pfn, pfn_type[pfn],
   1.175 -            (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
   1.176 -        goto out;
   1.177 -    }
   1.178 -
   1.179 -    ctxt.ctrlreg[3] = xen_pfn_to_cr3(p2m[pfn]);
   1.180  
   1.181      /* clear any pending events and the selector */
   1.182      memset(&(shared_info->evtchn_pending[0]), 0,
   1.183 @@ -870,17 +908,6 @@ int xc_linux_restore(int xc_handle, int 
   1.184  
   1.185      DPRINTF("Domain ready to be built.\n");
   1.186  
   1.187 -    domctl.cmd = XEN_DOMCTL_setvcpucontext;
   1.188 -    domctl.domain = (domid_t)dom;
   1.189 -    domctl.u.vcpucontext.vcpu   = 0;
   1.190 -    set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt);
   1.191 -    rc = xc_domctl(xc_handle, &domctl);
   1.192 -
   1.193 -    if (rc != 0) {
   1.194 -        ERROR("Couldn't build the domain");
   1.195 -        goto out;
   1.196 -    }
   1.197 -
   1.198   out:
   1.199      if ( (rc != 0) && (dom != 0) )
   1.200          xc_domain_destroy(xc_handle, dom);
     2.1 --- a/tools/libxc/xc_linux_save.c	Thu Mar 01 17:28:31 2007 +0000
     2.2 +++ b/tools/libxc/xc_linux_save.c	Thu Mar 01 17:59:17 2007 +0000
     2.3 @@ -696,6 +696,7 @@ int xc_linux_save(int xc_handle, int io_
     2.4      unsigned long needed_to_fix = 0;
     2.5      unsigned long total_sent    = 0;
     2.6  
     2.7 +    uint64_t vcpumap = 1ULL;
     2.8  
     2.9      /* If no explicit control parameters given, use defaults */
    2.10      if(!max_iters)
    2.11 @@ -716,25 +717,12 @@ int xc_linux_save(int xc_handle, int io_
    2.12          return 1;
    2.13      }
    2.14  
    2.15 -    if (lock_pages(&ctxt, sizeof(ctxt))) {
    2.16 -        ERROR("Unable to lock ctxt");
    2.17 -        return 1;
    2.18 -    }
    2.19 -
    2.20 -    /* Only have to worry about vcpu 0 even for SMP */
    2.21      if (xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt)) {
    2.22          ERROR("Could not get vcpu context");
    2.23          goto out;
    2.24      }
    2.25      shared_info_frame = info.shared_info_frame;
    2.26  
    2.27 -    /* A cheesy test to see whether the domain contains valid state. */
    2.28 -    if (ctxt.ctrlreg[3] == 0)
    2.29 -    {
    2.30 -        ERROR("Domain is not in a valid Linux guest OS state");
    2.31 -        goto out;
    2.32 -    }
    2.33 -
    2.34      /* Map the shared info frame */
    2.35      if(!(live_shinfo = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE,
    2.36                                              PROT_READ, shared_info_frame))) {
    2.37 @@ -1194,6 +1182,32 @@ int xc_linux_save(int xc_handle, int io_
    2.38  
    2.39      DPRINTF("All memory is saved\n");
    2.40  
    2.41 +    {
    2.42 +        struct {
    2.43 +            int minustwo;
    2.44 +            int max_vcpu_id;
    2.45 +            uint64_t vcpumap;
    2.46 +        } chunk = { -2, info.max_vcpu_id };
    2.47 +
    2.48 +        if (info.max_vcpu_id >= 64) {
    2.49 +            ERROR("Too many VCPUS in guest!");
    2.50 +            goto out;
    2.51 +        }
    2.52 +
    2.53 +        for (i = 1; i <= info.max_vcpu_id; i++) {
    2.54 +            xc_vcpuinfo_t vinfo;
    2.55 +            if ((xc_vcpu_getinfo(xc_handle, dom, i, &vinfo) == 0) &&
    2.56 +                vinfo.online)
    2.57 +                vcpumap |= 1ULL << i;
    2.58 +        }
    2.59 +
    2.60 +        chunk.vcpumap = vcpumap;
    2.61 +        if(!write_exact(io_fd, &chunk, sizeof(chunk))) {
    2.62 +            ERROR("Error when writing to state file (errno %d)", errno);
    2.63 +            goto out;
    2.64 +        }
    2.65 +    }
    2.66 +
    2.67      /* Zero terminate */
    2.68      i = 0;
    2.69      if (!write_exact(io_fd, &i, sizeof(int))) {
    2.70 @@ -1240,30 +1254,43 @@ int xc_linux_save(int xc_handle, int io_
    2.71          goto out;
    2.72      }
    2.73  
    2.74 -    /* Canonicalise each GDT frame number. */
    2.75 -    for ( i = 0; (512*i) < ctxt.gdt_ents; i++ ) {
    2.76 -        if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[i]) ) {
    2.77 -            ERROR("GDT frame is not in range of pseudophys map");
    2.78 +    for (i = 0; i <= info.max_vcpu_id; i++) {
    2.79 +        if (!(vcpumap & (1ULL << i)))
    2.80 +            continue;
    2.81 +
    2.82 +        if ((i != 0) && xc_vcpu_getcontext(xc_handle, dom, i, &ctxt)) {
    2.83 +            ERROR("No context for VCPU%d", i);
    2.84 +            goto out;
    2.85 +        }
    2.86 +
    2.87 +        /* Canonicalise each GDT frame number. */
    2.88 +        for ( j = 0; (512*j) < ctxt.gdt_ents; j++ ) {
    2.89 +            if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[j]) ) {
    2.90 +                ERROR("GDT frame is not in range of pseudophys map");
    2.91 +                goto out;
    2.92 +            }
    2.93 +        }
    2.94 +
    2.95 +        /* Canonicalise the page table base pointer. */
    2.96 +        if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[3])) ) {
    2.97 +            ERROR("PT base is not in range of pseudophys map");
    2.98 +            goto out;
    2.99 +        }
   2.100 +        ctxt.ctrlreg[3] = 
   2.101 +            xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[3])));
   2.102 +
   2.103 +        if (!write_exact(io_fd, &ctxt, sizeof(ctxt))) {
   2.104 +            ERROR("Error when writing to state file (1) (errno %d)", errno);
   2.105              goto out;
   2.106          }
   2.107      }
   2.108  
   2.109 -    /* Canonicalise the page table base pointer. */
   2.110 -    if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[3])) ) {
   2.111 -        ERROR("PT base is not in range of pseudophys map");
   2.112 -        goto out;
   2.113 -    }
   2.114 -    ctxt.ctrlreg[3] = 
   2.115 -        xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[3])));
   2.116 -
   2.117      /*
   2.118       * Reset the MFN to be a known-invalid value. See map_frame_list_list().
   2.119       */
   2.120      memcpy(page, live_shinfo, PAGE_SIZE);
   2.121      ((shared_info_t *)page)->arch.pfn_to_mfn_frame_list_list = 0;
   2.122 -
   2.123 -    if (!write_exact(io_fd, &ctxt, sizeof(ctxt)) ||
   2.124 -        !write_exact(io_fd, page, PAGE_SIZE)) {
   2.125 +    if (!write_exact(io_fd, page, PAGE_SIZE)) {
   2.126          ERROR("Error when writing to state file (1) (errno %d)", errno);
   2.127          goto out;
   2.128      }