ia64/xen-unstable

changeset 17050:0164d924ceba

Tools: fix save/restore of 32-bit PV guests with 64-bit tools
by removing some obvious typos, handling CR3 folding and hvirt_start
based on guest word-size, and understanding 32-bit INVALID_MFN.

Signed-off-by: Tim Deegan <Tim.Deegan@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Wed Feb 13 10:43:13 2008 +0000 (2008-02-13)
parents 27314cfbcefe
children 5e1df44d406e
files tools/libxc/xc_domain_restore.c tools/libxc/xc_domain_save.c tools/libxc/xg_private.h tools/libxc/xg_save_restore.h
line diff
     1.1 --- a/tools/libxc/xc_domain_restore.c	Wed Feb 13 10:42:09 2008 +0000
     1.2 +++ b/tools/libxc/xc_domain_restore.c	Wed Feb 13 10:43:13 2008 +0000
     1.3 @@ -251,7 +251,7 @@ static xen_pfn_t *load_p2m_frame_list(
     1.4  
     1.5      /* Now that we know the guest's word-size, can safely allocate 
     1.6       * the p2m frame list */
     1.7 -    if ( (p2m_frame_list = malloc(P2M_FL_SIZE)) == NULL )
     1.8 +    if ( (p2m_frame_list = malloc(P2M_TOOLS_FL_SIZE)) == NULL )
     1.9      {
    1.10          ERROR("Couldn't allocate p2m_frame_list array");
    1.11          return NULL;
    1.12 @@ -1040,7 +1040,7 @@ int xc_domain_restore(int xc_handle, int
    1.13              SET_FIELD(&ctxt, gdt_frames[j], p2m[pfn]);
    1.14          }
    1.15          /* Uncanonicalise the page table base pointer. */
    1.16 -        pfn = xen_cr3_to_pfn(GET_FIELD(&ctxt, ctrlreg[3]));
    1.17 +        pfn = UNFOLD_CR3(GET_FIELD(&ctxt, ctrlreg[3]));
    1.18  
    1.19          if ( pfn >= p2m_size )
    1.20          {
    1.21 @@ -1057,12 +1057,12 @@ int xc_domain_restore(int xc_handle, int
    1.22                    (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
    1.23              goto out;
    1.24          }
    1.25 -        SET_FIELD(&ctxt, ctrlreg[3], xen_pfn_to_cr3(p2m[pfn]));
    1.26 +        SET_FIELD(&ctxt, ctrlreg[3], FOLD_CR3(p2m[pfn]));
    1.27  
    1.28          /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
    1.29          if ( (pt_levels == 4) && (ctxt.x64.ctrlreg[1] & 1) )
    1.30          {
    1.31 -            pfn = xen_cr3_to_pfn(ctxt.x64.ctrlreg[1] & ~1);
    1.32 +            pfn = UNFOLD_CR3(ctxt.x64.ctrlreg[1] & ~1);
    1.33              if ( pfn >= p2m_size )
    1.34              {
    1.35                  ERROR("User PT base is bad: pfn=%lu p2m_size=%lu",
    1.36 @@ -1077,7 +1077,7 @@ int xc_domain_restore(int xc_handle, int
    1.37                        (unsigned long)pt_levels<<XEN_DOMCTL_PFINFO_LTAB_SHIFT);
    1.38                  goto out;
    1.39              }
    1.40 -            ctxt.x64.ctrlreg[1] = xen_pfn_to_cr3(p2m[pfn]);
    1.41 +            ctxt.x64.ctrlreg[1] = FOLD_CR3(p2m[pfn]);
    1.42          }
    1.43          domctl.cmd = XEN_DOMCTL_setvcpucontext;
    1.44          domctl.domain = (domid_t)dom;
    1.45 @@ -1158,7 +1158,7 @@ int xc_domain_restore(int xc_handle, int
    1.46      if ( guest_width > sizeof (xen_pfn_t) )
    1.47          for ( i = p2m_size - 1; i >= 0; i-- )
    1.48              ((uint64_t *)p2m)[i] = p2m[i];
    1.49 -    else if ( guest_width > sizeof (xen_pfn_t) )
    1.50 +    else if ( guest_width < sizeof (xen_pfn_t) )
    1.51          for ( i = 0; i < p2m_size; i++ )   
    1.52              ((uint32_t *)p2m)[i] = p2m[i];
    1.53  
     2.1 --- a/tools/libxc/xc_domain_save.c	Wed Feb 13 10:42:09 2008 +0000
     2.2 +++ b/tools/libxc/xc_domain_save.c	Wed Feb 13 10:43:13 2008 +0000
     2.3 @@ -61,10 +61,11 @@ unsigned int guest_width;
     2.4  
     2.5  #define mfn_to_pfn(_mfn)  (live_m2p[(_mfn)])
     2.6  
     2.7 -#define pfn_to_mfn(_pfn)                                \
     2.8 -  ((xen_pfn_t) ((guest_width==8)                       \
     2.9 -                ? (((uint64_t *)live_p2m)[(_pfn)])      \
    2.10 -                : (((uint32_t *)live_p2m)[(_pfn)])))
    2.11 +#define pfn_to_mfn(_pfn)                                            \
    2.12 +  ((xen_pfn_t) ((guest_width==8)                                    \
    2.13 +                ? (((uint64_t *)live_p2m)[(_pfn)])                  \
    2.14 +                : ((((uint32_t *)live_p2m)[(_pfn)]) == 0xffffffffU  \
    2.15 +                   ? (-1UL) : (((uint32_t *)live_p2m)[(_pfn)]))))
    2.16  
    2.17  /*
    2.18   * Returns TRUE if the given machine frame number has a unique mapping
    2.19 @@ -496,10 +497,9 @@ static int canonicalize_pagetable(unsign
    2.20          xen_start = L3_PAGETABLE_ENTRIES_PAE;
    2.21  
    2.22      /*
    2.23 -    ** in PAE only the L2 mapping the top 1GB contains Xen mappings.
    2.24 -    ** We can spot this by looking for the guest linear mapping which
    2.25 -    ** Xen always ensures is present in that L2. Guests must ensure
    2.26 -    ** that this check will fail for other L2s.
    2.27 +    ** In PAE only the L2 mapping the top 1GB contains Xen mappings.
    2.28 +    ** We can spot this by looking for the guest's mappingof the m2p.
    2.29 +    ** Guests must ensure that this check will fail for other L2s.
    2.30      */
    2.31      if ( (pt_levels == 3) && (type == XEN_DOMCTL_PFINFO_L2TAB) )
    2.32      {
    2.33 @@ -555,7 +555,13 @@ static int canonicalize_pagetable(unsign
    2.34                  /* This will happen if the type info is stale which
    2.35                     is quite feasible under live migration */
    2.36                  pfn  = 0;  /* zap it - we'll retransmit this page later */
    2.37 -                race = 1;  /* inform the caller of race; fatal if !live */ 
    2.38 +                /* XXX: We can't spot Xen mappings in compat-mode L2es 
    2.39 +                 * from 64-bit tools, but the only thing in them is the
    2.40 +                 * compat m2p, so we quietly zap them.  This doesn't
    2.41 +                 * count as a race, so don't report it. */
    2.42 +                if ( !(type == XEN_DOMCTL_PFINFO_L2TAB 
    2.43 +                       && sizeof (unsigned long) > guest_width) )
    2.44 +                     race = 1;  /* inform the caller; fatal if !live */ 
    2.45              }
    2.46              else
    2.47                  pfn = mfn_to_pfn(mfn);
    2.48 @@ -690,7 +696,7 @@ static xen_pfn_t *map_and_save_p2m_table
    2.49              else
    2.50                  p2m_frame_list_list[i] = 0;
    2.51      else if ( guest_width < sizeof(unsigned long) )
    2.52 -        for ( i = PAGE_SIZE/sizeof(unsigned long) - 1; i >= 0; i++ )
    2.53 +        for ( i = PAGE_SIZE/sizeof(unsigned long) - 1; i >= 0; i-- )
    2.54              p2m_frame_list_list[i] = ((uint32_t *)p2m_frame_list_list)[i];
    2.55  
    2.56      live_p2m_frame_list =
    2.57 @@ -704,19 +710,20 @@ static xen_pfn_t *map_and_save_p2m_table
    2.58      }
    2.59  
    2.60      /* Get a local copy of the live_P2M_frame_list */
    2.61 -    if ( !(p2m_frame_list = malloc(P2M_FL_SIZE)) )
    2.62 +    if ( !(p2m_frame_list = malloc(P2M_TOOLS_FL_SIZE)) )
    2.63      {
    2.64          ERROR("Couldn't allocate p2m_frame_list array");
    2.65          goto out;
    2.66      }
    2.67 -    memcpy(p2m_frame_list, live_p2m_frame_list, P2M_FL_SIZE);
    2.68 +    memset(p2m_frame_list, 0, P2M_TOOLS_FL_SIZE);
    2.69 +    memcpy(p2m_frame_list, live_p2m_frame_list, P2M_GUEST_FL_SIZE);
    2.70  
    2.71      /* Canonicalize guest's unsigned long vs ours */
    2.72      if ( guest_width > sizeof(unsigned long) )
    2.73          for ( i = 0; i < P2M_FL_ENTRIES; i++ )
    2.74              p2m_frame_list[i] = ((uint64_t *)p2m_frame_list)[i];
    2.75      else if ( guest_width < sizeof(unsigned long) )
    2.76 -        for ( i = P2M_FL_ENTRIES - 1; i >= 0; i++ )
    2.77 +        for ( i = P2M_FL_ENTRIES - 1; i >= 0; i-- )
    2.78              p2m_frame_list[i] = ((uint32_t *)p2m_frame_list)[i];
    2.79  
    2.80  
    2.81 @@ -1559,31 +1566,26 @@ int xc_domain_save(int xc_handle, int io
    2.82          }
    2.83  
    2.84          /* Canonicalise the page table base pointer. */
    2.85 -        if ( !MFN_IS_IN_PSEUDOPHYS_MAP(xen_cr3_to_pfn(
    2.86 -                                          GET_FIELD(&ctxt, ctrlreg[3]))) )
    2.87 +        if ( !MFN_IS_IN_PSEUDOPHYS_MAP(UNFOLD_CR3(
    2.88 +                                           GET_FIELD(&ctxt, ctrlreg[3]))) )
    2.89          {
    2.90              ERROR("PT base is not in range of pseudophys map");
    2.91              goto out;
    2.92          }
    2.93          SET_FIELD(&ctxt, ctrlreg[3], 
    2.94 -            xen_pfn_to_cr3(
    2.95 -                mfn_to_pfn(
    2.96 -                    xen_cr3_to_pfn(
    2.97 -                        GET_FIELD(&ctxt, ctrlreg[3])))));
    2.98 +            FOLD_CR3(mfn_to_pfn(UNFOLD_CR3(GET_FIELD(&ctxt, ctrlreg[3])))));
    2.99  
   2.100          /* Guest pagetable (x86/64) stored in otherwise-unused CR1. */
   2.101          if ( (pt_levels == 4) && ctxt.x64.ctrlreg[1] )
   2.102          {
   2.103 -            if ( !MFN_IS_IN_PSEUDOPHYS_MAP(
   2.104 -                     xen_cr3_to_pfn(ctxt.x64.ctrlreg[1])) )
   2.105 +            if ( !MFN_IS_IN_PSEUDOPHYS_MAP(UNFOLD_CR3(ctxt.x64.ctrlreg[1])) )
   2.106              {
   2.107                  ERROR("PT base is not in range of pseudophys map");
   2.108                  goto out;
   2.109              }
   2.110              /* Least-significant bit means 'valid PFN'. */
   2.111              ctxt.x64.ctrlreg[1] = 1 |
   2.112 -                xen_pfn_to_cr3(
   2.113 -                    mfn_to_pfn(xen_cr3_to_pfn(ctxt.x64.ctrlreg[1])));
   2.114 +                FOLD_CR3(mfn_to_pfn(UNFOLD_CR3(ctxt.x64.ctrlreg[1])));
   2.115          }
   2.116  
   2.117          if ( write_exact(io_fd, &ctxt, ((guest_width==8) 
     3.1 --- a/tools/libxc/xg_private.h	Wed Feb 13 10:42:09 2008 +0000
     3.2 +++ b/tools/libxc/xg_private.h	Wed Feb 13 10:43:13 2008 +0000
     3.3 @@ -155,7 +155,9 @@ typedef l4_pgentry_64_t l4_pgentry_t;
     3.4  #define P2M_FL_ENTRIES  (((p2m_size)+FPP-1)/FPP)
     3.5  
     3.6  /* Size in bytes of the pfn_to_mfn_frame_list     */
     3.7 -#define P2M_FL_SIZE     ((P2M_FL_ENTRIES)*(guest_width))
     3.8 +#define P2M_GUEST_FL_SIZE ((P2M_FL_ENTRIES) * (guest_width))
     3.9 +#define P2M_TOOLS_FL_SIZE ((P2M_FL_ENTRIES) *                           \
    3.10 +                           MAX((sizeof (xen_pfn_t)), guest_width))
    3.11  
    3.12  /* Masks for PTE<->PFN conversions */
    3.13  #define MADDR_BITS_X86  ((guest_width == 8) ? 52 : 44)
     4.1 --- a/tools/libxc/xg_save_restore.h	Wed Feb 13 10:42:09 2008 +0000
     4.2 +++ b/tools/libxc/xg_save_restore.h	Wed Feb 13 10:43:13 2008 +0000
     4.3 @@ -68,6 +68,13 @@ static inline int get_platform_info(int 
     4.4  
     4.5      *guest_width = domctl.u.address_size.size / 8;
     4.6  
     4.7 +    /* 64-bit tools will see the 64-bit hvirt_start, but 32-bit guests 
     4.8 +     * will be using the compat one. */
     4.9 +    if ( *guest_width < sizeof (unsigned long) )
    4.10 +        /* XXX need to fix up a way of extracting this value from Xen if
    4.11 +         * XXX it becomes variable for domU */
    4.12 +        *hvirt_start = 0xf5800000;
    4.13 +
    4.14      if (strstr(xen_caps, "xen-3.0-x86_64"))
    4.15          /* Depends on whether it's a compat 32-on-64 guest */
    4.16          *pt_levels = ( (*guest_width == 8) ? 4 : 3 );
    4.17 @@ -136,6 +143,16 @@ typedef union
    4.18          (_p)->x32._f = (_v);                    \
    4.19  } while (0)
    4.20  
    4.21 +#define UNFOLD_CR3(_c)                                                  \
    4.22 +  ((uint64_t)((guest_width == 8)                                        \
    4.23 +              ? ((_c) >> 12)                                            \
    4.24 +              : (((uint32_t)(_c) >> 12) | ((uint32_t)(_c) << 20))))
    4.25 +
    4.26 +#define FOLD_CR3(_c)                                                    \
    4.27 +  ((uint64_t)((guest_width == 8)                                        \
    4.28 +              ? ((uint64_t)(_c)) << 12                                  \
    4.29 +              : (((uint32_t)(_c) << 12) | ((uint32_t)(_c) >> 20))))
    4.30 +
    4.31  #define MEMCPY_FIELD(_d, _s, _f) do {                              \
    4.32      if (guest_width == 8)                                          \
    4.33          memcpy(&(_d)->x64._f, &(_s)->x64._f,sizeof((_d)->x64._f)); \