ia64/xen-unstable

changeset 15941:4c8394e3b011

[TOOLS] Make xc_domain_{save, restore} understand compat guests
Signed-off-by: Tim Deegan <Tim.Deegan@xensource.com>
author Tim Deegan <Tim.Deegan@xensource.com>
date Wed Sep 19 17:44:23 2007 +0100 (2007-09-19)
parents 177ebf350b4c
children 1902a21dd1ae
files tools/libxc/xc_core.c tools/libxc/xc_core_x86.c tools/libxc/xc_domain_restore.c tools/libxc/xc_domain_save.c tools/libxc/xc_resume.c tools/libxc/xg_private.h tools/libxc/xg_save_restore.h
line diff
     1.1 --- a/tools/libxc/xc_core.c	Wed Sep 19 15:42:56 2007 +0100
     1.2 +++ b/tools/libxc/xc_core.c	Wed Sep 19 17:44:23 2007 +0100
     1.3 @@ -58,6 +58,9 @@
     1.4  /* number of pages to write at a time */
     1.5  #define DUMP_INCREMENT (4 * 1024)
     1.6  
     1.7 +/* Don't yet support cross-address-size core dump */
     1.8 +#define guest_width (sizeof (unsigned long))
     1.9 +
    1.10  /* string table */
    1.11  struct xc_core_strtab {
    1.12      char       *strings;
     2.1 --- a/tools/libxc/xc_core_x86.c	Wed Sep 19 15:42:56 2007 +0100
     2.2 +++ b/tools/libxc/xc_core_x86.c	Wed Sep 19 17:44:23 2007 +0100
     2.3 @@ -21,6 +21,9 @@
     2.4  #include "xg_private.h"
     2.5  #include "xc_core.h"
     2.6  
     2.7 +/* Don't yet support cross-address-size core dump */
     2.8 +#define guest_width (sizeof (unsigned long))
     2.9 +
    2.10  static int nr_gpfns(int xc_handle, domid_t domid)
    2.11  {
    2.12      return xc_memory_op(xc_handle, XENMEM_maximum_gpfn, &domid) + 1;
     3.1 --- a/tools/libxc/xc_domain_restore.c	Wed Sep 19 15:42:56 2007 +0100
     3.2 +++ b/tools/libxc/xc_domain_restore.c	Wed Sep 19 17:44:23 2007 +0100
     3.3 @@ -56,6 +56,10 @@ static xen_pfn_t *p2m = NULL;
     3.4  /* A table of P2M mappings in the current region */
     3.5  static xen_pfn_t *p2m_batch = NULL;
     3.6  
     3.7 +/* Address size of the guest, in bytes */
     3.8 +unsigned int guest_width;
     3.9 +
    3.10 +
    3.11  static ssize_t
    3.12  read_exact(int fd, void *buf, size_t count)
    3.13  {
    3.14 @@ -168,22 +172,17 @@ static int uncanonicalize_pagetable(int 
    3.15  static xen_pfn_t *load_p2m_frame_list(int io_fd, int *pae_extended_cr3)
    3.16  {
    3.17      xen_pfn_t *p2m_frame_list;
    3.18 -    vcpu_guest_context_t ctxt;
    3.19 +    vcpu_guest_context_either_t ctxt;
    3.20 +    xen_pfn_t p2m_fl_zero;
    3.21  
    3.22 -    if ( (p2m_frame_list = malloc(P2M_FL_SIZE)) == NULL )
    3.23 -    {
    3.24 -        ERROR("Couldn't allocate p2m_frame_list array");
    3.25 -        return NULL;
    3.26 -    }
    3.27 -    
    3.28      /* Read first entry of P2M list, or extended-info signature (~0UL). */
    3.29 -    if ( !read_exact(io_fd, p2m_frame_list, sizeof(long)) )
    3.30 +    if ( !read_exact(io_fd, &p2m_fl_zero, sizeof(long)) )
    3.31      {
    3.32          ERROR("read extended-info signature failed");
    3.33          return NULL;
    3.34      }
    3.35      
    3.36 -    if ( p2m_frame_list[0] == ~0UL )
    3.37 +    if ( p2m_fl_zero == ~0UL )
    3.38      {
    3.39          uint32_t tot_bytes;
    3.40          
    3.41 @@ -211,25 +210,42 @@ static xen_pfn_t *load_p2m_frame_list(in
    3.42              /* VCPU context structure? */
    3.43              if ( !strncmp(chunk_sig, "vcpu", 4) )
    3.44              {
    3.45 -                if ( !read_exact(io_fd, &ctxt, sizeof(ctxt)) )
    3.46 +                /* Pick a guest word-size and PT depth from the ctxt size */
    3.47 +                if ( chunk_bytes == sizeof (ctxt.x32) )
    3.48 +                {
    3.49 +                    guest_width = 4;
    3.50 +                    if ( pt_levels > 2 ) 
    3.51 +                        pt_levels = 3; 
    3.52 +                }
    3.53 +                else if ( chunk_bytes == sizeof (ctxt.x64) )
    3.54 +                {
    3.55 +                    guest_width = 8;
    3.56 +                    pt_levels = 4;
    3.57 +                }
    3.58 +                else 
    3.59 +                {
    3.60 +                    ERROR("bad extended-info context size %d", chunk_bytes);
    3.61 +                    return NULL;
    3.62 +                }
    3.63 +
    3.64 +                if ( !read_exact(io_fd, &ctxt, chunk_bytes) )
    3.65                  {
    3.66                      ERROR("read extended-info vcpu context failed");
    3.67                      return NULL;
    3.68                  }
    3.69 -                tot_bytes   -= sizeof(struct vcpu_guest_context);
    3.70 -                chunk_bytes -= sizeof(struct vcpu_guest_context);
    3.71 -                
    3.72 -                if ( ctxt.vm_assist & (1UL << VMASST_TYPE_pae_extended_cr3) )
    3.73 +                tot_bytes -= chunk_bytes;
    3.74 +                chunk_bytes = 0;
    3.75 +
    3.76 +                if ( GET_FIELD(&ctxt, vm_assist) 
    3.77 +                     & (1UL << VMASST_TYPE_pae_extended_cr3) )
    3.78                      *pae_extended_cr3 = 1;
    3.79              }
    3.80              
    3.81              /* Any remaining bytes of this chunk: read and discard. */
    3.82              while ( chunk_bytes )
    3.83              {
    3.84 -                unsigned long sz = chunk_bytes;
    3.85 -                if ( sz > P2M_FL_SIZE )
    3.86 -                    sz = P2M_FL_SIZE;
    3.87 -                if ( !read_exact(io_fd, p2m_frame_list, sz) )
    3.88 +                unsigned long sz = MIN(chunk_bytes, sizeof(xen_pfn_t));
    3.89 +                if ( !read_exact(io_fd, &p2m_fl_zero, sz) )
    3.90                  {
    3.91                      ERROR("read-and-discard extended-info chunk bytes failed");
    3.92                      return NULL;
    3.93 @@ -240,15 +256,25 @@ static xen_pfn_t *load_p2m_frame_list(in
    3.94          }
    3.95  
    3.96          /* Now read the real first entry of P2M list. */
    3.97 -        if ( !read_exact(io_fd, p2m_frame_list, sizeof(long)) )
    3.98 +        if ( !read_exact(io_fd, &p2m_fl_zero, sizeof(xen_pfn_t)) )
    3.99          {
   3.100              ERROR("read first entry of p2m_frame_list failed");
   3.101              return NULL;
   3.102          }
   3.103      }
   3.104  
   3.105 -    /* First entry is already read into the p2m array. */
   3.106 -    if ( !read_exact(io_fd, &p2m_frame_list[1], P2M_FL_SIZE - sizeof(long)) )
   3.107 +    /* Now that we know the guest's word-size, can safely allocate 
   3.108 +     * the p2m frame list */
   3.109 +    if ( (p2m_frame_list = malloc(P2M_FL_SIZE)) == NULL )
   3.110 +    {
   3.111 +        ERROR("Couldn't allocate p2m_frame_list array");
   3.112 +        return NULL;
   3.113 +    }
   3.114 +
   3.115 +    /* First entry has already been read. */
   3.116 +    p2m_frame_list[0] = p2m_fl_zero;
   3.117 +    if ( !read_exact(io_fd, &p2m_frame_list[1], 
   3.118 +                     (P2M_FL_ENTRIES - 1) * sizeof(xen_pfn_t)) )
   3.119      {
   3.120          ERROR("read p2m_frame_list failed");
   3.121          return NULL;
   3.122 @@ -272,11 +298,11 @@ int xc_domain_restore(int xc_handle, int
   3.123      /* The new domain's shared-info frame number. */
   3.124      unsigned long shared_info_frame;
   3.125      unsigned char shared_info_page[PAGE_SIZE]; /* saved contents from file */
   3.126 -    shared_info_t *old_shared_info = (shared_info_t *)shared_info_page;
   3.127 -    shared_info_t *new_shared_info;
   3.128 +    shared_info_either_t *old_shared_info = (shared_info_either_t *)shared_info_page;
   3.129 +    shared_info_either_t *new_shared_info;
   3.130  
   3.131      /* A copy of the CPU context of the guest. */
   3.132 -    vcpu_guest_context_t ctxt;
   3.133 +    vcpu_guest_context_either_t ctxt;
   3.134  
   3.135      /* A table containing the type of each PFN (/not/ MFN!). */
   3.136      unsigned long *pfn_type = NULL;
   3.137 @@ -291,7 +317,7 @@ int xc_domain_restore(int xc_handle, int
   3.138      xen_pfn_t *p2m_frame_list = NULL;
   3.139      
   3.140      /* A temporary mapping of the guest's start_info page. */
   3.141 -    start_info_t *start_info;
   3.142 +    start_info_either_t *start_info;
   3.143  
   3.144      /* Our mapping of the current region (batch) */
   3.145      char *region_base;
   3.146 @@ -324,16 +350,38 @@ int xc_domain_restore(int xc_handle, int
   3.147      }
   3.148      DPRINTF("xc_domain_restore start: p2m_size = %lx\n", p2m_size);
   3.149  
   3.150 -    if ( !hvm )
   3.151 +    if ( !get_platform_info(xc_handle, dom,
   3.152 +                            &max_mfn, &hvirt_start, &pt_levels, &guest_width) )
   3.153      {
   3.154 -        /*
   3.155 -         * XXX For now, 32bit dom0's can only save/restore 32bit domUs
   3.156 -         * on 64bit hypervisors.
   3.157 -         */
   3.158 +        ERROR("Unable to get platform info.");
   3.159 +        return 1;
   3.160 +    }
   3.161 +    
   3.162 +    /* The *current* word size of the guest isn't very interesting; for now
   3.163 +     * assume the guest will be the same as we are.  We'll fix that later
   3.164 +     * if we discover otherwise. */
   3.165 +    guest_width = sizeof(unsigned long);
   3.166 +    pt_levels = (guest_width == 8) ? 4 : (pt_levels == 2) ? 2 : 3; 
   3.167 +    
   3.168 +    if ( lock_pages(&ctxt, sizeof(ctxt)) )
   3.169 +    {
   3.170 +        /* needed for build domctl, but might as well do early */
   3.171 +        ERROR("Unable to lock ctxt");
   3.172 +        return 1;
   3.173 +    }
   3.174 +
   3.175 +    if ( !hvm ) 
   3.176 +    {
   3.177 +        /* Load the p2m frame list, plus potential extended info chunk */
   3.178 +        p2m_frame_list = load_p2m_frame_list(io_fd, &pae_extended_cr3);
   3.179 +        if ( !p2m_frame_list )
   3.180 +            goto out;
   3.181 +
   3.182 +        /* Now that we know the word size, tell Xen about it */
   3.183          memset(&domctl, 0, sizeof(domctl));
   3.184          domctl.domain = dom;
   3.185          domctl.cmd    = XEN_DOMCTL_set_address_size;
   3.186 -        domctl.u.address_size.size = sizeof(unsigned long) * 8;
   3.187 +        domctl.u.address_size.size = guest_width * 8;
   3.188          rc = do_domctl(xc_handle, &domctl);
   3.189          if ( rc != 0 )
   3.190          {
   3.191 @@ -343,30 +391,8 @@ int xc_domain_restore(int xc_handle, int
   3.192          rc = 1;
   3.193      }
   3.194  
   3.195 -    if ( !get_platform_info(xc_handle, dom,
   3.196 -                            &max_mfn, &hvirt_start, &pt_levels) )
   3.197 -    {
   3.198 -        ERROR("Unable to get platform info.");
   3.199 -        return 1;
   3.200 -    }
   3.201 -
   3.202 -    if ( lock_pages(&ctxt, sizeof(ctxt)) )
   3.203 -    {
   3.204 -        /* needed for build domctl, but might as well do early */
   3.205 -        ERROR("Unable to lock ctxt");
   3.206 -        return 1;
   3.207 -    }
   3.208 -
   3.209 -    /* Load the p2m frame list, plus potential extended info chunk */
   3.210 -    if ( !hvm ) 
   3.211 -    {
   3.212 -        p2m_frame_list = load_p2m_frame_list(io_fd, &pae_extended_cr3);
   3.213 -        if ( !p2m_frame_list )
   3.214 -            goto out;
   3.215 -    }
   3.216 -
   3.217      /* We want zeroed memory so use calloc rather than malloc. */
   3.218 -    p2m        = calloc(p2m_size, sizeof(xen_pfn_t));
   3.219 +    p2m        = calloc(p2m_size, MAX(guest_width, sizeof (xen_pfn_t))); 
   3.220      pfn_type   = calloc(p2m_size, sizeof(unsigned long));
   3.221      region_mfn = calloc(MAX_BATCH_SIZE, sizeof(xen_pfn_t));
   3.222      p2m_batch  = calloc(MAX_BATCH_SIZE, sizeof(xen_pfn_t));
   3.223 @@ -963,14 +989,16 @@ int xc_domain_restore(int xc_handle, int
   3.224          if ( !(vcpumap & (1ULL << i)) )
   3.225              continue;
   3.226  
   3.227 -        if ( !read_exact(io_fd, &ctxt, sizeof(ctxt)) )
   3.228 +        if ( !read_exact(io_fd, &ctxt, ((guest_width == 8)
   3.229 +                                        ? sizeof(ctxt.x64)
   3.230 +                                        : sizeof(ctxt.x32))) )
   3.231          {
   3.232              ERROR("Error when reading ctxt %d", i);
   3.233              goto out;
   3.234          }
   3.235  
   3.236          if ( !new_ctxt_format )
   3.237 -            ctxt.flags |= VGCF_online;
   3.238 +            SET_FIELD(&ctxt, flags, GET_FIELD(&ctxt, flags) | VGCF_online);
   3.239  
   3.240          if ( i == 0 )
   3.241          {
   3.242 @@ -978,48 +1006,49 @@ int xc_domain_restore(int xc_handle, int
   3.243               * Uncanonicalise the suspend-record frame number and poke
   3.244               * resume record.
   3.245               */
   3.246 -            pfn = ctxt.user_regs.edx;
   3.247 +            pfn = GET_FIELD(&ctxt, user_regs.edx);
   3.248              if ( (pfn >= p2m_size) ||
   3.249                   (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB) )
   3.250              {
   3.251                  ERROR("Suspend record frame number is bad");
   3.252                  goto out;
   3.253              }
   3.254 -            ctxt.user_regs.edx = mfn = p2m[pfn];
   3.255 +            mfn = p2m[pfn];
   3.256 +            SET_FIELD(&ctxt, user_regs.edx, mfn);
   3.257              start_info = xc_map_foreign_range(
   3.258                  xc_handle, dom, PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
   3.259 -            start_info->nr_pages = p2m_size;
   3.260 -            start_info->shared_info = shared_info_frame << PAGE_SHIFT;
   3.261 -            start_info->flags = 0;
   3.262 -            *store_mfn = start_info->store_mfn = p2m[start_info->store_mfn];
   3.263 -            start_info->store_evtchn = store_evtchn;
   3.264 -            start_info->console.domU.mfn = p2m[start_info->console.domU.mfn];
   3.265 -            start_info->console.domU.evtchn = console_evtchn;
   3.266 -            *console_mfn = start_info->console.domU.mfn;
   3.267 +            SET_FIELD(start_info, nr_pages, p2m_size);
   3.268 +            SET_FIELD(start_info, shared_info, shared_info_frame<<PAGE_SHIFT);
   3.269 +            SET_FIELD(start_info, flags, 0);
   3.270 +            *store_mfn = p2m[GET_FIELD(start_info, store_mfn)];
   3.271 +            SET_FIELD(start_info, store_mfn, *store_mfn);
   3.272 +            SET_FIELD(start_info, store_evtchn, store_evtchn);
   3.273 +            *console_mfn = p2m[GET_FIELD(start_info, console.domU.mfn)];
   3.274 +            SET_FIELD(start_info, console.domU.mfn, *console_mfn);
   3.275 +            SET_FIELD(start_info, console.domU.evtchn, console_evtchn);
   3.276              munmap(start_info, PAGE_SIZE);
   3.277          }
   3.278 -
   3.279          /* Uncanonicalise each GDT frame number. */
   3.280 -        if ( ctxt.gdt_ents > 8192 )
   3.281 +        if ( GET_FIELD(&ctxt, gdt_ents) > 8192 )
   3.282          {
   3.283              ERROR("GDT entry count out of range");
   3.284              goto out;
   3.285          }
   3.286  
   3.287 -        for ( j = 0; (512*j) < ctxt.gdt_ents; j++ )
   3.288 +        for ( j = 0; (512*j) < GET_FIELD(&ctxt, gdt_ents); j++ )
   3.289          {
   3.290 -            pfn = ctxt.gdt_frames[j];
   3.291 +            pfn = GET_FIELD(&ctxt, gdt_frames[j]);
   3.292              if ( (pfn >= p2m_size) ||
   3.293                   (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB) )
   3.294              {
   3.295 -                ERROR("GDT frame number is bad");
   3.296 +                ERROR("GDT frame number %i (0x%lx) is bad", 
   3.297 +                      j, (unsigned long)pfn);
   3.298                  goto out;
   3.299              }
   3.300 -            ctxt.gdt_frames[j] = p2m[pfn];
   3.301 +            SET_FIELD(&ctxt, gdt_frames[j], p2m[pfn]);
   3.302          }
   3.303 -
   3.304          /* Uncanonicalise the page table base pointer. */
   3.305 -        pfn = xen_cr3_to_pfn(ctxt.ctrlreg[3]);
   3.306 +        pfn = xen_cr3_to_pfn(GET_FIELD(&ctxt, ctrlreg[3]));
   3.307  
   3.308          if ( pfn >= p2m_size )
   3.309          {
   3.310 @@ -1036,21 +1065,18 @@ int xc_domain_restore(int xc_handle, int
   3.311                    (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
   3.312              goto out;
   3.313          }
   3.314 -
   3.315 -        ctxt.ctrlreg[3] = xen_pfn_to_cr3(p2m[pfn]);
   3.316 +        SET_FIELD(&ctxt, ctrlreg[3], xen_pfn_to_cr3(p2m[pfn]));
   3.317  
   3.318          /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
   3.319 -        if ( (pt_levels == 4) && ctxt.ctrlreg[1] )
   3.320 +        if ( (pt_levels == 4) && (ctxt.x64.ctrlreg[1] & 1) )
   3.321          {
   3.322 -            pfn = xen_cr3_to_pfn(ctxt.ctrlreg[1]);
   3.323 -
   3.324 +            pfn = xen_cr3_to_pfn(ctxt.x64.ctrlreg[1] & ~1);
   3.325              if ( pfn >= p2m_size )
   3.326              {
   3.327 -                ERROR("User PT base is bad: pfn=%lu p2m_size=%lu type=%08lx",
   3.328 -                      pfn, p2m_size, pfn_type[pfn]);
   3.329 +                ERROR("User PT base is bad: pfn=%lu p2m_size=%lu",
   3.330 +                      pfn, p2m_size);
   3.331                  goto out;
   3.332              }
   3.333 -
   3.334              if ( (pfn_type[pfn] & XEN_DOMCTL_PFINFO_LTABTYPE_MASK) !=
   3.335                   ((unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT) )
   3.336              {
   3.337 @@ -1059,14 +1085,12 @@ int xc_domain_restore(int xc_handle, int
   3.338                        (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
   3.339                  goto out;
   3.340              }
   3.341 -
   3.342 -            ctxt.ctrlreg[1] = xen_pfn_to_cr3(p2m[pfn]);
   3.343 +            ctxt.x64.ctrlreg[1] = xen_pfn_to_cr3(p2m[pfn]);
   3.344          }
   3.345 -
   3.346          domctl.cmd = XEN_DOMCTL_setvcpucontext;
   3.347          domctl.domain = (domid_t)dom;
   3.348          domctl.u.vcpucontext.vcpu = i;
   3.349 -        set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt);
   3.350 +        set_xen_guest_handle(domctl.u.vcpucontext.ctxt, &ctxt.c);
   3.351          rc = xc_domctl(xc_handle, &domctl);
   3.352          if ( rc != 0 )
   3.353          {
   3.354 @@ -1087,22 +1111,16 @@ int xc_domain_restore(int xc_handle, int
   3.355          xc_handle, dom, PAGE_SIZE, PROT_WRITE, shared_info_frame);
   3.356  
   3.357      /* restore saved vcpu_info and arch specific info */
   3.358 -    memcpy(&new_shared_info->vcpu_info,
   3.359 -	   &old_shared_info->vcpu_info,
   3.360 -	   sizeof(new_shared_info->vcpu_info));
   3.361 -    memcpy(&new_shared_info->arch,
   3.362 -	   &old_shared_info->arch,
   3.363 -	   sizeof(new_shared_info->arch));
   3.364 +    MEMCPY_FIELD(new_shared_info, old_shared_info, vcpu_info);
   3.365 +    MEMCPY_FIELD(new_shared_info, old_shared_info, arch);
   3.366  
   3.367      /* clear any pending events and the selector */
   3.368 -    memset(&(new_shared_info->evtchn_pending[0]), 0,
   3.369 -           sizeof (new_shared_info->evtchn_pending));
   3.370 +    MEMSET_ARRAY_FIELD(new_shared_info, evtchn_pending, 0);
   3.371      for ( i = 0; i < MAX_VIRT_CPUS; i++ )
   3.372 -        new_shared_info->vcpu_info[i].evtchn_pending_sel = 0;
   3.373 +	    SET_FIELD(new_shared_info, vcpu_info[i].evtchn_pending_sel, 0);
   3.374  
   3.375      /* mask event channels */
   3.376 -    memset(&(new_shared_info->evtchn_mask[0]), 0xff,
   3.377 -           sizeof (new_shared_info->evtchn_mask));
   3.378 +    MEMSET_ARRAY_FIELD(new_shared_info, evtchn_mask, 0xff);
   3.379  
   3.380      /* leave wallclock time. set by hypervisor */
   3.381      munmap(new_shared_info, PAGE_SIZE);
   3.382 @@ -1113,10 +1131,9 @@ int xc_domain_restore(int xc_handle, int
   3.383          pfn = p2m_frame_list[i];
   3.384          if ( (pfn >= p2m_size) || (pfn_type[pfn] != XEN_DOMCTL_PFINFO_NOTAB) )
   3.385          {
   3.386 -            ERROR("PFN-to-MFN frame number is bad");
   3.387 +            ERROR("PFN-to-MFN frame number %i (%#lx) is bad", i, pfn);
   3.388              goto out;
   3.389          }
   3.390 -
   3.391          p2m_frame_list[i] = p2m[pfn];
   3.392      }
   3.393  
   3.394 @@ -1128,8 +1145,17 @@ int xc_domain_restore(int xc_handle, int
   3.395          goto out;
   3.396      }
   3.397  
   3.398 -    memcpy(live_p2m, p2m, ROUNDUP(p2m_size * sizeof(xen_pfn_t), PAGE_SHIFT));
   3.399 -    munmap(live_p2m, ROUNDUP(p2m_size * sizeof(xen_pfn_t), PAGE_SHIFT));
   3.400 +    /* If the domain we're restoring has a different word size to ours,
   3.401 +     * we need to repack the p2m appropriately */
   3.402 +    if ( guest_width > sizeof (xen_pfn_t) )
   3.403 +        for ( i = p2m_size - 1; i >= 0; i-- )
   3.404 +            ((uint64_t *)p2m)[i] = p2m[i];
   3.405 +    else if ( guest_width > sizeof (xen_pfn_t) )
   3.406 +        for ( i = 0; i < p2m_size; i++ )   
   3.407 +            ((uint32_t *)p2m)[i] = p2m[i];
   3.408 +
   3.409 +    memcpy(live_p2m, p2m, ROUNDUP(p2m_size * guest_width, PAGE_SHIFT));
   3.410 +    munmap(live_p2m, ROUNDUP(p2m_size * guest_width, PAGE_SHIFT));
   3.411  
   3.412      DPRINTF("Domain ready to be built.\n");
   3.413      rc = 0;
     4.1 --- a/tools/libxc/xc_domain_save.c	Wed Sep 19 15:42:56 2007 +0100
     4.2 +++ b/tools/libxc/xc_domain_save.c	Wed Sep 19 17:44:23 2007 +0100
     4.3 @@ -54,9 +54,17 @@ static xen_pfn_t *live_p2m = NULL;
     4.4  static xen_pfn_t *live_m2p = NULL;
     4.5  static unsigned long m2p_mfn0;
     4.6  
     4.7 +/* Address size of the guest */
     4.8 +unsigned int guest_width;
     4.9 +
    4.10  /* grep fodder: machine_to_phys */
    4.11  
    4.12 -#define mfn_to_pfn(_mfn) live_m2p[(_mfn)]
    4.13 +#define mfn_to_pfn(_mfn)  (live_m2p[(_mfn)])
    4.14 +
    4.15 +#define pfn_to_mfn(_pfn)                                \
    4.16 +  ((xen_pfn_t) ((guest_width==8)                       \
    4.17 +                ? (((uint64_t *)live_p2m)[(_pfn)])      \
    4.18 +                : (((uint32_t *)live_p2m)[(_pfn)])))
    4.19  
    4.20  /*
    4.21   * Returns TRUE if the given machine frame number has a unique mapping
    4.22 @@ -65,19 +73,7 @@ static unsigned long m2p_mfn0;
    4.23  #define MFN_IS_IN_PSEUDOPHYS_MAP(_mfn)          \
    4.24      (((_mfn) < (max_mfn)) &&                    \
    4.25       ((mfn_to_pfn(_mfn) < (p2m_size)) &&        \
    4.26 -      (live_p2m[mfn_to_pfn(_mfn)] == (_mfn))))
    4.27 -
    4.28 -/* Returns TRUE if MFN is successfully converted to a PFN. */
    4.29 -#define translate_mfn_to_pfn(_pmfn)                             \
    4.30 -({                                                              \
    4.31 -    unsigned long mfn = *(_pmfn);                               \
    4.32 -    int _res = 1;                                               \
    4.33 -    if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )                       \
    4.34 -        _res = 0;                                               \
    4.35 -    else                                                        \
    4.36 -        *(_pmfn) = mfn_to_pfn(mfn);                             \
    4.37 -    _res;                                                       \
    4.38 -})
    4.39 +      (pfn_to_mfn(mfn_to_pfn(_mfn)) == (_mfn))))
    4.40  
    4.41  /*
    4.42  ** During (live) save/migrate, we maintain a number of bitmaps to track
    4.43 @@ -451,22 +447,25 @@ static int suspend_and_state(int (*suspe
    4.44  ** it to update the MFN to a reasonable value.
    4.45  */
    4.46  static void *map_frame_list_list(int xc_handle, uint32_t dom,
    4.47 -                                 shared_info_t *shinfo)
    4.48 +                                 shared_info_either_t *shinfo)
    4.49  {
    4.50      int count = 100;
    4.51      void *p;
    4.52 +    uint64_t fll = GET_FIELD(shinfo, arch.pfn_to_mfn_frame_list_list);
    4.53  
    4.54 -    while ( count-- && (shinfo->arch.pfn_to_mfn_frame_list_list == 0) )
    4.55 +    while ( count-- && (fll == 0) )
    4.56 +    {
    4.57          usleep(10000);
    4.58 +        fll = GET_FIELD(shinfo, arch.pfn_to_mfn_frame_list_list);
    4.59 +    }
    4.60  
    4.61 -    if ( shinfo->arch.pfn_to_mfn_frame_list_list == 0 )
    4.62 +    if ( fll == 0 )
    4.63      {
    4.64          ERROR("Timed out waiting for frame list updated.");
    4.65          return NULL;
    4.66      }
    4.67  
    4.68 -    p = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ,
    4.69 -                             shinfo->arch.pfn_to_mfn_frame_list_list);
    4.70 +    p = xc_map_foreign_range(xc_handle, dom, PAGE_SIZE, PROT_READ, fll);
    4.71      if ( p == NULL )
    4.72          ERROR("Couldn't map p2m_frame_list_list (errno %d)", errno);
    4.73  
    4.74 @@ -659,15 +658,16 @@ static xen_pfn_t *map_and_save_p2m_table
    4.75                                           int io_fd, 
    4.76                                           uint32_t dom,
    4.77                                           unsigned long p2m_size,
    4.78 -                                         shared_info_t *live_shinfo)
    4.79 +                                         shared_info_either_t *live_shinfo)
    4.80  {
    4.81 -    vcpu_guest_context_t ctxt;
    4.82 +    vcpu_guest_context_either_t ctxt;
    4.83  
    4.84      /* Double and single indirect references to the live P2M table */
    4.85 -    xen_pfn_t *live_p2m_frame_list_list = NULL;
    4.86 -    xen_pfn_t *live_p2m_frame_list = NULL;
    4.87 +    void *live_p2m_frame_list_list = NULL;
    4.88 +    void *live_p2m_frame_list = NULL;
    4.89  
    4.90 -    /* A copy of the pfn-to-mfn table frame list. */
    4.91 +    /* Copies of the above. */
    4.92 +    xen_pfn_t *p2m_frame_list_list = NULL;
    4.93      xen_pfn_t *p2m_frame_list = NULL;
    4.94  
    4.95      /* The mapping of the live p2m table itself */
    4.96 @@ -680,9 +680,28 @@ static xen_pfn_t *map_and_save_p2m_table
    4.97      if ( !live_p2m_frame_list_list )
    4.98          goto out;
    4.99  
   4.100 +    /* Get a local copy of the live_P2M_frame_list_list */
   4.101 +    if ( !(p2m_frame_list_list = malloc(PAGE_SIZE)) )
   4.102 +    {
   4.103 +        ERROR("Couldn't allocate p2m_frame_list_list array");
   4.104 +        goto out;
   4.105 +    }
   4.106 +    memcpy(p2m_frame_list_list, live_p2m_frame_list_list, PAGE_SIZE);
   4.107 +
   4.108 +    /* Canonicalize guest's unsigned long vs ours */
   4.109 +    if ( guest_width > sizeof(unsigned long) )
   4.110 +        for ( i = 0; i < PAGE_SIZE/sizeof(unsigned long); i++ )
   4.111 +            if ( i < PAGE_SIZE/guest_width )
   4.112 +                p2m_frame_list_list[i] = ((uint64_t *)p2m_frame_list_list)[i];
   4.113 +            else
   4.114 +                p2m_frame_list_list[i] = 0;
   4.115 +    else if ( guest_width < sizeof(unsigned long) )
   4.116 +        for ( i = PAGE_SIZE/sizeof(unsigned long) - 1; i >= 0; i++ )
   4.117 +            p2m_frame_list_list[i] = ((uint32_t *)p2m_frame_list_list)[i];
   4.118 +
   4.119      live_p2m_frame_list =
   4.120          xc_map_foreign_batch(xc_handle, dom, PROT_READ,
   4.121 -                             live_p2m_frame_list_list,
   4.122 +                             p2m_frame_list_list,
   4.123                               P2M_FLL_ENTRIES);
   4.124      if ( !live_p2m_frame_list )
   4.125      {
   4.126 @@ -690,6 +709,22 @@ static xen_pfn_t *map_and_save_p2m_table
   4.127          goto out;
   4.128      }
   4.129  
   4.130 +    /* Get a local copy of the live_P2M_frame_list */
   4.131 +    if ( !(p2m_frame_list = malloc(P2M_FL_SIZE)) )
   4.132 +    {
   4.133 +        ERROR("Couldn't allocate p2m_frame_list array");
   4.134 +        goto out;
   4.135 +    }
   4.136 +    memcpy(p2m_frame_list, live_p2m_frame_list, P2M_FL_SIZE);
   4.137 +
   4.138 +    /* Canonicalize guest's unsigned long vs ours */
   4.139 +    if ( guest_width > sizeof(unsigned long) )
   4.140 +        for ( i = 0; i < P2M_FL_ENTRIES; i++ )
   4.141 +            p2m_frame_list[i] = ((uint64_t *)p2m_frame_list)[i];
   4.142 +    else if ( guest_width < sizeof(unsigned long) )
   4.143 +        for ( i = P2M_FL_ENTRIES - 1; i >= 0; i++ )
   4.144 +            p2m_frame_list[i] = ((uint32_t *)p2m_frame_list)[i];
   4.145 +
   4.146  
   4.147      /* Map all the frames of the pfn->mfn table. For migrate to succeed,
   4.148         the guest must not change which frames are used for this purpose.
   4.149 @@ -697,7 +732,7 @@ static xen_pfn_t *map_and_save_p2m_table
   4.150         from a safety POV anyhow. */
   4.151  
   4.152      p2m = xc_map_foreign_batch(xc_handle, dom, PROT_READ,
   4.153 -                               live_p2m_frame_list,
   4.154 +                               p2m_frame_list,
   4.155                                 P2M_FL_ENTRIES);
   4.156      if ( !p2m )
   4.157      {
   4.158 @@ -706,27 +741,30 @@ static xen_pfn_t *map_and_save_p2m_table
   4.159      }
   4.160      live_p2m = p2m; /* So that translation macros will work */
   4.161      
   4.162 -    /* Get a local copy of the live_P2M_frame_list */
   4.163 -    if ( !(p2m_frame_list = malloc(P2M_FL_SIZE)) )
   4.164 +    /* Canonicalise the pfn-to-mfn table frame-number list. */
   4.165 +    for ( i = 0; i < p2m_size; i += FPP )
   4.166      {
   4.167 -        ERROR("Couldn't allocate p2m_frame_list array");
   4.168 -        goto out;
   4.169 -    }
   4.170 -    memcpy(p2m_frame_list, live_p2m_frame_list, P2M_FL_SIZE);
   4.171 -
   4.172 -    /* Canonicalise the pfn-to-mfn table frame-number list. */
   4.173 -    for ( i = 0; i < p2m_size; i += fpp )
   4.174 -    {
   4.175 -        if ( !translate_mfn_to_pfn(&p2m_frame_list[i/fpp]) )
   4.176 +        if ( !MFN_IS_IN_PSEUDOPHYS_MAP(p2m_frame_list[i/FPP]) )
   4.177          {
   4.178              ERROR("Frame# in pfn-to-mfn frame list is not in pseudophys");
   4.179 -            ERROR("entry %d: p2m_frame_list[%ld] is 0x%"PRIx64, i, i/fpp,
   4.180 -                  (uint64_t)p2m_frame_list[i/fpp]);
   4.181 +            ERROR("entry %d: p2m_frame_list[%ld] is 0x%"PRIx64", max 0x%lx",
   4.182 +                  i, i/FPP, (uint64_t)p2m_frame_list[i/FPP], max_mfn);
   4.183 +            if ( p2m_frame_list[i/FPP] < max_mfn ) 
   4.184 +            {
   4.185 +                ERROR("m2p[0x%"PRIx64"] = 0x%"PRIx64, 
   4.186 +                      (uint64_t)p2m_frame_list[i/FPP],
   4.187 +                      (uint64_t)live_m2p[p2m_frame_list[i/FPP]]);
   4.188 +                ERROR("p2m[0x%"PRIx64"] = 0x%"PRIx64, 
   4.189 +                      (uint64_t)live_m2p[p2m_frame_list[i/FPP]],
   4.190 +                      (uint64_t)p2m[live_m2p[p2m_frame_list[i/FPP]]]);
   4.191 +
   4.192 +            }
   4.193              goto out;
   4.194          }
   4.195 +        p2m_frame_list[i/FPP] = mfn_to_pfn(p2m_frame_list[i/FPP]);
   4.196      }
   4.197  
   4.198 -    if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt) )
   4.199 +    if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt.c) )
   4.200      {
   4.201          ERROR("Could not get vcpu context");
   4.202          goto out;
   4.203 @@ -737,25 +775,26 @@ static xen_pfn_t *map_and_save_p2m_table
   4.204       * a PAE guest understands extended CR3 (PDPTs above 4GB). Turns off
   4.205       * slow paths in the restore code.
   4.206       */
   4.207 -    if ( (pt_levels == 3) &&
   4.208 -         (ctxt.vm_assist & (1UL << VMASST_TYPE_pae_extended_cr3)) )
   4.209      {
   4.210          unsigned long signature = ~0UL;
   4.211 -        uint32_t tot_sz   = sizeof(struct vcpu_guest_context) + 8;
   4.212 -        uint32_t chunk_sz = sizeof(struct vcpu_guest_context);
   4.213 +        uint32_t chunk_sz = ((guest_width==8) 
   4.214 +                             ? sizeof(ctxt.x64) 
   4.215 +                             : sizeof(ctxt.x32));
   4.216 +        uint32_t tot_sz   = chunk_sz + 8;
   4.217          char chunk_sig[]  = "vcpu";
   4.218          if ( !write_exact(io_fd, &signature, sizeof(signature)) ||
   4.219               !write_exact(io_fd, &tot_sz,    sizeof(tot_sz)) ||
   4.220               !write_exact(io_fd, &chunk_sig, 4) ||
   4.221               !write_exact(io_fd, &chunk_sz,  sizeof(chunk_sz)) ||
   4.222 -             !write_exact(io_fd, &ctxt,      sizeof(ctxt)) )
   4.223 +             !write_exact(io_fd, &ctxt,      chunk_sz) )
   4.224          {
   4.225              ERROR("write: extended info");
   4.226              goto out;
   4.227          }
   4.228      }
   4.229  
   4.230 -    if ( !write_exact(io_fd, p2m_frame_list, P2M_FL_SIZE) )
   4.231 +    if ( !write_exact(io_fd, p2m_frame_list, 
   4.232 +                      P2M_FL_ENTRIES * sizeof(xen_pfn_t)) )
   4.233      {
   4.234          ERROR("write: p2m_frame_list");
   4.235          goto out;
   4.236 @@ -774,6 +813,9 @@ static xen_pfn_t *map_and_save_p2m_table
   4.237      if ( live_p2m_frame_list )
   4.238          munmap(live_p2m_frame_list, P2M_FLL_ENTRIES * PAGE_SIZE);
   4.239  
   4.240 +    if ( p2m_frame_list_list ) 
   4.241 +        free(p2m_frame_list_list);
   4.242 +
   4.243      if ( p2m_frame_list ) 
   4.244          free(p2m_frame_list);
   4.245  
   4.246 @@ -798,7 +840,7 @@ int xc_domain_save(int xc_handle, int io
   4.247      unsigned long shared_info_frame;
   4.248  
   4.249      /* A copy of the CPU context of the guest. */
   4.250 -    vcpu_guest_context_t ctxt;
   4.251 +    vcpu_guest_context_either_t ctxt;
   4.252  
   4.253      /* A table containing the type of each PFN (/not/ MFN!). */
   4.254      unsigned long *pfn_type = NULL;
   4.255 @@ -808,7 +850,7 @@ int xc_domain_save(int xc_handle, int io
   4.256      char page[PAGE_SIZE];
   4.257  
   4.258      /* Live mapping of shared info structure */
   4.259 -    shared_info_t *live_shinfo = NULL;
   4.260 +    shared_info_either_t *live_shinfo = NULL;
   4.261  
   4.262      /* base of the region in which domain memory is mapped */
   4.263      unsigned char *region_base = NULL;
   4.264 @@ -836,6 +878,8 @@ int xc_domain_save(int xc_handle, int io
   4.265      /* HVM: magic frames for ioreqs and xenstore comms. */
   4.266      uint64_t magic_pfns[3]; /* ioreq_pfn, bufioreq_pfn, store_pfn */
   4.267  
   4.268 +    unsigned long mfn;
   4.269 +
   4.270      /* If no explicit control parameters given, use defaults */
   4.271      max_iters  = max_iters  ? : DEF_MAX_ITERS;
   4.272      max_factor = max_factor ? : DEF_MAX_FACTOR;
   4.273 @@ -843,7 +887,7 @@ int xc_domain_save(int xc_handle, int io
   4.274      initialize_mbit_rate();
   4.275  
   4.276      if ( !get_platform_info(xc_handle, dom,
   4.277 -                            &max_mfn, &hvirt_start, &pt_levels) )
   4.278 +                            &max_mfn, &hvirt_start, &pt_levels, &guest_width) )
   4.279      {
   4.280          ERROR("Unable to get platform info.");
   4.281          return 1;
   4.282 @@ -1006,7 +1050,6 @@ int xc_domain_save(int xc_handle, int io
   4.283      if ( !hvm )
   4.284      {
   4.285          int err = 0;
   4.286 -        unsigned long mfn;
   4.287  
   4.288          /* Map the P2M table, and write the list of P2M frames */
   4.289          live_p2m = map_and_save_p2m_table(xc_handle, io_fd, dom, 
   4.290 @@ -1023,7 +1066,7 @@ int xc_domain_save(int xc_handle, int io
   4.291          
   4.292          for ( i = 0; i < p2m_size; i++ )
   4.293          {
   4.294 -            mfn = live_p2m[i];
   4.295 +            mfn = pfn_to_mfn(i);
   4.296              if( (mfn != INVALID_P2M_ENTRY) && (mfn_to_pfn(mfn) != i) )
   4.297              {
   4.298                  DPRINTF("i=0x%x mfn=%lx live_m2p=%lx\n", i,
   4.299 @@ -1083,11 +1126,16 @@ int xc_domain_save(int xc_handle, int io
   4.300                  int n = permute(N, p2m_size, order_nr);
   4.301  
   4.302                  if ( debug )
   4.303 -                    DPRINTF("%d pfn= %08lx mfn= %08lx %d  [mfn]= %08lx\n",
   4.304 -                            iter, (unsigned long)n, hvm ? 0 : live_p2m[n],
   4.305 -                            test_bit(n, to_send),
   4.306 -                            hvm ? 0 : mfn_to_pfn(live_p2m[n]&0xFFFFF));
   4.307 -
   4.308 +                {
   4.309 +                    DPRINTF("%d pfn= %08lx mfn= %08lx %d",
   4.310 +                            iter, (unsigned long)n,
   4.311 +                            hvm ? 0 : pfn_to_mfn(n),
   4.312 +                            test_bit(n, to_send));
   4.313 +                    if ( !hvm && is_mapped(pfn_to_mfn(n)) )
   4.314 +                        DPRINTF("  [mfn]= %08lx",
   4.315 +                                mfn_to_pfn(pfn_to_mfn(n)&0xFFFFF));
   4.316 +                    DPRINTF("\n");
   4.317 +                }
   4.318                  if ( !last_iter &&
   4.319                       test_bit(n, to_send) &&
   4.320                       test_bit(n, to_skip) )
   4.321 @@ -1118,7 +1166,7 @@ int xc_domain_save(int xc_handle, int io
   4.322                  if ( hvm ) 
   4.323                      pfn_type[batch] = n;
   4.324                  else
   4.325 -                    pfn_type[batch] = live_p2m[n];
   4.326 +                    pfn_type[batch] = pfn_to_mfn(n);
   4.327                      
   4.328                  if ( !is_mapped(pfn_type[batch]) )
   4.329                  {
   4.330 @@ -1451,7 +1499,7 @@ int xc_domain_save(int xc_handle, int io
   4.331  
   4.332          for ( i = 0, j = 0; i < p2m_size; i++ )
   4.333          {
   4.334 -            if ( !is_mapped(live_p2m[i]) )
   4.335 +            if ( !is_mapped(pfn_to_mfn(i)) )
   4.336                  j++;
   4.337          }
   4.338  
   4.339 @@ -1463,7 +1511,7 @@ int xc_domain_save(int xc_handle, int io
   4.340  
   4.341          for ( i = 0, j = 0; i < p2m_size; )
   4.342          {
   4.343 -            if ( !is_mapped(live_p2m[i]) )
   4.344 +            if ( !is_mapped(pfn_to_mfn(i)) )
   4.345                  pfntab[j++] = i;
   4.346  
   4.347              i++;
   4.348 @@ -1480,63 +1528,75 @@ int xc_domain_save(int xc_handle, int io
   4.349          }
   4.350      }
   4.351  
   4.352 -    if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt) )
   4.353 +    if ( xc_vcpu_getcontext(xc_handle, dom, 0, &ctxt.c) )
   4.354      {
   4.355          ERROR("Could not get vcpu context");
   4.356          goto out;
   4.357      }
   4.358  
   4.359      /* Canonicalise the suspend-record frame number. */
   4.360 -    if ( !translate_mfn_to_pfn(&ctxt.user_regs.edx) )
   4.361 +    mfn = GET_FIELD(&ctxt, user_regs.edx);
   4.362 +    if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
   4.363      {
   4.364          ERROR("Suspend record is not in range of pseudophys map");
   4.365          goto out;
   4.366      }
   4.367 +    SET_FIELD(&ctxt, user_regs.edx, mfn_to_pfn(mfn));
   4.368  
   4.369      for ( i = 0; i <= info.max_vcpu_id; i++ )
   4.370      {
   4.371          if ( !(vcpumap & (1ULL << i)) )
   4.372              continue;
   4.373  
   4.374 -        if ( (i != 0) && xc_vcpu_getcontext(xc_handle, dom, i, &ctxt) )
   4.375 +        if ( (i != 0) && xc_vcpu_getcontext(xc_handle, dom, i, &ctxt.c) )
   4.376          {
   4.377              ERROR("No context for VCPU%d", i);
   4.378              goto out;
   4.379          }
   4.380  
   4.381          /* Canonicalise each GDT frame number. */
   4.382 -        for ( j = 0; (512*j) < ctxt.gdt_ents; j++ )
   4.383 +        for ( j = 0; (512*j) < GET_FIELD(&ctxt, gdt_ents); j++ )
   4.384          {
   4.385 -            if ( !translate_mfn_to_pfn(&ctxt.gdt_frames[j]) )
   4.386 +            mfn = GET_FIELD(&ctxt, gdt_frames[j]);
   4.387 +            if ( !MFN_IS_IN_PSEUDOPHYS_MAP(mfn) )
   4.388              {
   4.389                  ERROR("GDT frame is not in range of pseudophys map");
   4.390                  goto out;
   4.391              }
   4.392 +            SET_FIELD(&ctxt, gdt_frames[j], mfn_to_pfn(mfn));
   4.393          }
   4.394  
   4.395          /* Canonicalise the page table base pointer. */
   4.396 -        if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[3])) )
   4.397 +        if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(
   4.398 +                                          GET_FIELD(&ctxt, ctrlreg[3]))) )
   4.399          {
   4.400              ERROR("PT base is not in range of pseudophys map");
   4.401              goto out;
   4.402          }
   4.403 -        ctxt.ctrlreg[3] = 
   4.404 -            xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[3])));
   4.405 +        SET_FIELD(&ctxt, ctrlreg[3], 
   4.406 +            xen_pfn_to_cr3(
   4.407 +                mfn_to_pfn(
   4.408 +                    xen_cr3_to_pfn(
   4.409 +                        GET_FIELD(&ctxt, ctrlreg[3])))));
   4.410  
   4.411          /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
   4.412 -        if ( (pt_levels == 4) && ctxt.ctrlreg[1] )
   4.413 +        if ( (pt_levels == 4) && ctxt.x64.ctrlreg[1] )
   4.414          {
   4.415 -            if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(ctxt.ctrlreg[1])) )
   4.416 +            if ( !MFN_IS_IN_PSEUDOPHYS_MAP(
   4.417 +                     xen_cr3_to_pfn(ctxt.x64.ctrlreg[1])) )
   4.418              {
   4.419                  ERROR("PT base is not in range of pseudophys map");
   4.420                  goto out;
   4.421              }
   4.422              /* Least-significant bit means 'valid PFN'. */
   4.423 -            ctxt.ctrlreg[1] = 1 |
   4.424 -                xen_pfn_to_cr3(mfn_to_pfn(xen_cr3_to_pfn(ctxt.ctrlreg[1])));
   4.425 +            ctxt.x64.ctrlreg[1] = 1 |
   4.426 +                xen_pfn_to_cr3(
   4.427 +                    mfn_to_pfn(xen_cr3_to_pfn(ctxt.x64.ctrlreg[1])));
   4.428          }
   4.429  
   4.430 -        if ( !write_exact(io_fd, &ctxt, sizeof(ctxt)) )
   4.431 +        if ( !write_exact(io_fd, &ctxt, ((guest_width==8) 
   4.432 +                                         ? sizeof(ctxt.x64) 
   4.433 +                                         : sizeof(ctxt.x32))) )
   4.434          {
   4.435              ERROR("Error when writing to state file (1) (errno %d)", errno);
   4.436              goto out;
   4.437 @@ -1547,7 +1607,8 @@ int xc_domain_save(int xc_handle, int io
   4.438       * Reset the MFN to be a known-invalid value. See map_frame_list_list().
   4.439       */
   4.440      memcpy(page, live_shinfo, PAGE_SIZE);
   4.441 -    ((shared_info_t *)page)->arch.pfn_to_mfn_frame_list_list = 0;
   4.442 +    SET_FIELD(((shared_info_either_t *)page), 
   4.443 +              arch.pfn_to_mfn_frame_list_list, 0);
   4.444      if ( !write_exact(io_fd, page, PAGE_SIZE) )
   4.445      {
   4.446          ERROR("Error when writing to state file (1) (errno %d)", errno);
     5.1 --- a/tools/libxc/xc_resume.c	Wed Sep 19 15:42:56 2007 +0100
     5.2 +++ b/tools/libxc/xc_resume.c	Wed Sep 19 17:44:23 2007 +0100
     5.3 @@ -8,13 +8,8 @@
     5.4  #include <xen/foreign/x86_64.h>
     5.5  #include <xen/hvm/params.h>
     5.6  
     5.7 -/* Need to provide the right flavour of vcpu context for Xen */
     5.8 -typedef union
     5.9 -{
    5.10 -    vcpu_guest_context_x86_64_t c64;
    5.11 -    vcpu_guest_context_x86_32_t c32;   
    5.12 -    vcpu_guest_context_t c;
    5.13 -} vcpu_guest_context_either_t;
    5.14 +/* Don't yet support cross-address-size uncooperative resume */
    5.15 +#define guest_width (sizeof (unsigned long))
    5.16  
    5.17  static int modify_returncode(int xc_handle, uint32_t domid)
    5.18  {
    5.19 @@ -50,9 +45,9 @@ static int modify_returncode(int xc_hand
    5.20      if ( !info.hvm )
    5.21          ctxt.c.user_regs.eax = 1;
    5.22      else if ( strstr(caps, "x86_64") )
    5.23 -        ctxt.c64.user_regs.eax = 1;
    5.24 +        ctxt.x64.user_regs.eax = 1;
    5.25      else
    5.26 -        ctxt.c32.user_regs.eax = 1;
    5.27 +        ctxt.x32.user_regs.eax = 1;
    5.28  
    5.29      if ( (rc = xc_vcpu_setcontext(xc_handle, domid, 0, &ctxt.c)) != 0 )
    5.30          return rc;
     6.1 --- a/tools/libxc/xg_private.h	Wed Sep 19 15:42:56 2007 +0100
     6.2 +++ b/tools/libxc/xg_private.h	Wed Sep 19 17:44:23 2007 +0100
     6.3 @@ -133,13 +133,6 @@ typedef l4_pgentry_64_t l4_pgentry_t;
     6.4  #define PAGE_SHIFT_X86          12
     6.5  #define PAGE_SIZE_X86           (1UL << PAGE_SHIFT_X86)
     6.6  #define PAGE_MASK_X86           (~(PAGE_SIZE_X86-1))
     6.7 -#if defined(__i386__)
     6.8 -#define MADDR_BITS_X86          44
     6.9 -#elif defined(__x86_64__)
    6.10 -#define MADDR_BITS_X86          52
    6.11 -#endif
    6.12 -#define MFN_MASK_X86            ((1ULL << (MADDR_BITS_X86 - PAGE_SHIFT_X86)) - 1)
    6.13 -#define MADDR_MASK_X86          (MFN_MASK_X86 << PAGE_SHIFT_X86)
    6.14  
    6.15  #define PAGE_SHIFT_IA64         14
    6.16  #define PAGE_SIZE_IA64          (1UL << PAGE_SHIFT_IA64)
    6.17 @@ -147,19 +140,28 @@ typedef l4_pgentry_64_t l4_pgentry_t;
    6.18  
    6.19  #define ROUNDUP(_x,_w) (((unsigned long)(_x)+(1UL<<(_w))-1) & ~((1UL<<(_w))-1))
    6.20  
    6.21 +
    6.22 +/* XXX SMH: following skanky macros rely on variable p2m_size being set */
    6.23 +/* XXX TJD: also, "guest_width" should be the guest's sizeof(unsigned long) */
    6.24 +
    6.25  /* Number of xen_pfn_t in a page */
    6.26 -#define fpp             (PAGE_SIZE/sizeof(xen_pfn_t))
    6.27  
    6.28 -/* XXX SMH: following 3 skanky macros rely on variable p2m_size being set */
    6.29 +#define FPP             (PAGE_SIZE/(guest_width))
    6.30  
    6.31  /* Number of entries in the pfn_to_mfn_frame_list_list */
    6.32 -#define P2M_FLL_ENTRIES (((p2m_size)+(fpp*fpp)-1)/(fpp*fpp))
    6.33 +#define P2M_FLL_ENTRIES (((p2m_size)+(FPP*FPP)-1)/(FPP*FPP))
    6.34  
    6.35  /* Number of entries in the pfn_to_mfn_frame_list */
    6.36 -#define P2M_FL_ENTRIES  (((p2m_size)+fpp-1)/fpp)
    6.37 +#define P2M_FL_ENTRIES  (((p2m_size)+FPP-1)/FPP)
    6.38  
    6.39  /* Size in bytes of the pfn_to_mfn_frame_list     */
    6.40 -#define P2M_FL_SIZE     ((P2M_FL_ENTRIES)*sizeof(unsigned long))
    6.41 +#define P2M_FL_SIZE     ((P2M_FL_ENTRIES)*(guest_width))
    6.42 +
    6.43 +/* Masks for PTE<->PFN conversions */
    6.44 +#define MADDR_BITS_X86  ((guest_width == 8) ? 52 : 44)
    6.45 +#define MFN_MASK_X86    ((1ULL << (MADDR_BITS_X86 - PAGE_SHIFT_X86)) - 1)
    6.46 +#define MADDR_MASK_X86  (MFN_MASK_X86 << PAGE_SHIFT_X86)
    6.47 +
    6.48  
    6.49  #define PAEKERN_no           0
    6.50  #define PAEKERN_yes          1
     7.1 --- a/tools/libxc/xg_save_restore.h	Wed Sep 19 15:42:56 2007 +0100
     7.2 +++ b/tools/libxc/xg_save_restore.h	Wed Sep 19 17:44:23 2007 +0100
     7.3 @@ -6,6 +6,9 @@
     7.4  
     7.5  #include "xc_private.h"
     7.6  
     7.7 +#include <xen/foreign/x86_32.h>
     7.8 +#include <xen/foreign/x86_64.h>
     7.9 +
    7.10  /*
    7.11  ** We process save/restore/migrate in batches of pages; the below
    7.12  ** determines how many pages we (at maximum) deal with in each batch.
    7.13 @@ -32,15 +35,19 @@
    7.14  **      be a property of the domain, but for the moment we just read it
    7.15  **      from the hypervisor.
    7.16  **
    7.17 +**    - The width of a guest word (unsigned long), in bytes.
    7.18 +**
    7.19  ** Returns 1 on success, 0 on failure.
    7.20  */
    7.21  static inline int get_platform_info(int xc_handle, uint32_t dom,
    7.22                                      /* OUT */ unsigned long *max_mfn,
    7.23                                      /* OUT */ unsigned long *hvirt_start,
    7.24 -                                    /* OUT */ unsigned int *pt_levels)
    7.25 +                                    /* OUT */ unsigned int *pt_levels,
    7.26 +                                    /* OUT */ unsigned int *guest_width)
    7.27  {
    7.28      xen_capabilities_info_t xen_caps = "";
    7.29      xen_platform_parameters_t xen_params;
    7.30 +    DECLARE_DOMCTL;
    7.31  
    7.32      if (xc_version(xc_handle, XENVER_platform_parameters, &xen_params) != 0)
    7.33          return 0;
    7.34 @@ -52,17 +59,18 @@ static inline int get_platform_info(int 
    7.35  
    7.36      *hvirt_start = xen_params.virt_start;
    7.37  
    7.38 -    /*
    7.39 -     * XXX For now, 32bit dom0's can only save/restore 32bit domUs
    7.40 -     * on 64bit hypervisors, so no need to check which type of domain
    7.41 -     * we're dealing with.
    7.42 -     */
    7.43 +    memset(&domctl, 0, sizeof(domctl));
    7.44 +    domctl.domain = dom;
    7.45 +    domctl.cmd = XEN_DOMCTL_get_address_size;
    7.46 +
    7.47 +    if ( do_domctl(xc_handle, &domctl) != 0 )
    7.48 +        return 0; 
    7.49 +
    7.50 +    *guest_width = domctl.u.address_size.size / 8;
    7.51 +
    7.52      if (strstr(xen_caps, "xen-3.0-x86_64"))
    7.53 -#if defined(__i386__)
    7.54 -        *pt_levels = 3;
    7.55 -#else
    7.56 -        *pt_levels = 4;
    7.57 -#endif
    7.58 +        /* Depends on whether it's a compat 32-on-64 guest */
    7.59 +        *pt_levels = ( (*guest_width == 8) ? 4 : 3 );
    7.60      else if (strstr(xen_caps, "xen-3.0-x86_32p"))
    7.61          *pt_levels = 3;
    7.62      else if (strstr(xen_caps, "xen-3.0-x86_32"))
    7.63 @@ -95,3 +103,56 @@ static inline int get_platform_info(int 
    7.64  
    7.65  /* Returns TRUE if the PFN is currently mapped */
    7.66  #define is_mapped(pfn_type) (!((pfn_type) & 0x80000000UL))
    7.67 +
    7.68 +
    7.69 +/* 32-on-64 support: saving 32bit guests from 64bit tools and vice versa */
    7.70 +typedef union 
    7.71 +{
    7.72 +    vcpu_guest_context_x86_64_t x64;
    7.73 +    vcpu_guest_context_x86_32_t x32;   
    7.74 +    vcpu_guest_context_t c;
    7.75 +} vcpu_guest_context_either_t;
    7.76 +
    7.77 +typedef union 
    7.78 +{
    7.79 +    shared_info_x86_64_t x64;
    7.80 +    shared_info_x86_32_t x32;   
    7.81 +    shared_info_t s;
    7.82 +} shared_info_either_t;
    7.83 +
    7.84 +typedef union 
    7.85 +{
    7.86 +    start_info_x86_64_t x64;
    7.87 +    start_info_x86_32_t x32;   
    7.88 +    start_info_t s;
    7.89 +} start_info_either_t;
    7.90 +
    7.91 +#define GET_FIELD(_p, _f) ((guest_width==8) ? ((_p)->x64._f) : ((_p)->x32._f))
    7.92 +
    7.93 +#define SET_FIELD(_p, _f, _v) do {              \
    7.94 +    if (guest_width == 8)                       \
    7.95 +        (_p)->x64._f = (_v);                    \
    7.96 +    else                                        \
    7.97 +        (_p)->x32._f = (_v);                    \
    7.98 +} while (0)
    7.99 +
   7.100 +#define MEMCPY_FIELD(_d, _s, _f) do {                              \
   7.101 +    if (guest_width == 8)                                          \
   7.102 +        memcpy(&(_d)->x64._f, &(_s)->x64._f,sizeof((_d)->x64._f)); \
   7.103 +    else                                                           \
   7.104 +        memcpy(&(_d)->x32._f, &(_s)->x32._f,sizeof((_d)->x32._f)); \
   7.105 +} while (0)
   7.106 +
   7.107 +#define MEMSET_ARRAY_FIELD(_p, _f, _v) do {                        \
   7.108 +    if (guest_width == 8)                                          \
   7.109 +        memset(&(_p)->x64._f[0], (_v), sizeof((_p)->x64._f));      \
   7.110 +    else                                                           \
   7.111 +        memset(&(_p)->x32._f[0], (_v), sizeof((_p)->x32._f));      \
   7.112 +} while (0)
   7.113 +
   7.114 +#ifndef MAX
   7.115 +#define MAX(_a, _b) ((_a) >= (_b) ? (_a) : (_b))
   7.116 +#endif
   7.117 +#ifndef MIN
   7.118 +#define MIN(_a, _b) ((_a) <= (_b) ? (_a) : (_b))
   7.119 +#endif