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>
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)); \