ia64/xen-unstable

changeset 16719:fba4e7357744

x86: Allow batched mmu updates which preserve accessed/dirty pte bits.
Signed-off-by: Bruce Rogers <brogers@novell.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jan 15 14:32:15 2008 +0000 (2008-01-15)
parents 58dfcad8d56d
children d13c4d2836a8
files xen/arch/x86/mm.c xen/include/public/xen.h
line diff
     1.1 --- a/xen/arch/x86/mm.c	Tue Jan 15 14:27:15 2008 +0000
     1.2 +++ b/xen/arch/x86/mm.c	Tue Jan 15 14:32:15 2008 +0000
     1.3 @@ -1342,21 +1342,30 @@ static inline int update_intpte(intpte_t
     1.4                                  intpte_t old, 
     1.5                                  intpte_t new,
     1.6                                  unsigned long mfn,
     1.7 -                                struct vcpu *v)
     1.8 +                                struct vcpu *v,
     1.9 +                                int preserve_ad)
    1.10  {
    1.11      int rv = 1;
    1.12  #ifndef PTE_UPDATE_WITH_CMPXCHG
    1.13 -    rv = paging_write_guest_entry(v, p, new, _mfn(mfn));
    1.14 -#else
    1.15 +    if ( !preserve_ad )
    1.16 +    {
    1.17 +        rv = paging_write_guest_entry(v, p, new, _mfn(mfn));
    1.18 +    }
    1.19 +    else
    1.20 +#endif
    1.21      {
    1.22          intpte_t t = old;
    1.23          for ( ; ; )
    1.24          {
    1.25 -            rv = paging_cmpxchg_guest_entry(v, p, &t, new, _mfn(mfn));
    1.26 +            intpte_t _new = new;
    1.27 +            if ( preserve_ad )
    1.28 +                _new |= old & (_PAGE_ACCESSED | _PAGE_DIRTY);
    1.29 +
    1.30 +            rv = paging_cmpxchg_guest_entry(v, p, &t, _new, _mfn(mfn));
    1.31              if ( unlikely(rv == 0) )
    1.32              {
    1.33                  MEM_LOG("Failed to update %" PRIpte " -> %" PRIpte
    1.34 -                        ": saw %" PRIpte, old, new, t);
    1.35 +                        ": saw %" PRIpte, old, _new, t);
    1.36                  break;
    1.37              }
    1.38  
    1.39 @@ -1369,20 +1378,19 @@ static inline int update_intpte(intpte_t
    1.40              old = t;
    1.41          }
    1.42      }
    1.43 -#endif
    1.44      return rv;
    1.45  }
    1.46  
    1.47  /* Macro that wraps the appropriate type-changes around update_intpte().
    1.48   * Arguments are: type, ptr, old, new, mfn, vcpu */
    1.49 -#define UPDATE_ENTRY(_t,_p,_o,_n,_m,_v)                             \
    1.50 +#define UPDATE_ENTRY(_t,_p,_o,_n,_m,_v,_ad)                         \
    1.51      update_intpte(&_t ## e_get_intpte(*(_p)),                       \
    1.52                    _t ## e_get_intpte(_o), _t ## e_get_intpte(_n),   \
    1.53 -                  (_m), (_v))
    1.54 +                  (_m), (_v), (_ad))
    1.55  
    1.56  /* Update the L1 entry at pl1e to new value nl1e. */
    1.57  static int mod_l1_entry(l1_pgentry_t *pl1e, l1_pgentry_t nl1e, 
    1.58 -                        unsigned long gl1mfn)
    1.59 +                        unsigned long gl1mfn, int preserve_ad)
    1.60  {
    1.61      l1_pgentry_t ol1e;
    1.62      struct vcpu *curr = current;
    1.63 @@ -1393,7 +1401,7 @@ static int mod_l1_entry(l1_pgentry_t *pl
    1.64          return 0;
    1.65  
    1.66      if ( unlikely(paging_mode_refcounts(d)) )
    1.67 -        return UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr);
    1.68 +        return UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr, preserve_ad);
    1.69  
    1.70      if ( l1e_get_flags(nl1e) & _PAGE_PRESENT )
    1.71      {
    1.72 @@ -1415,12 +1423,14 @@ static int mod_l1_entry(l1_pgentry_t *pl
    1.73  
    1.74          /* Fast path for identical mapping, r/w and presence. */
    1.75          if ( !l1e_has_changed(ol1e, nl1e, _PAGE_RW | _PAGE_PRESENT) )
    1.76 -            return UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr);
    1.77 +            return UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr,
    1.78 +                                preserve_ad);
    1.79  
    1.80          if ( unlikely(!get_page_from_l1e(nl1e, FOREIGNDOM)) )
    1.81              return 0;
    1.82          
    1.83 -        if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr)) )
    1.84 +        if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr,
    1.85 +                                    preserve_ad)) )
    1.86          {
    1.87              put_page_from_l1e(nl1e, d);
    1.88              return 0;
    1.89 @@ -1428,7 +1438,8 @@ static int mod_l1_entry(l1_pgentry_t *pl
    1.90      }
    1.91      else
    1.92      {
    1.93 -        if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr)) )
    1.94 +        if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, curr,
    1.95 +                                    preserve_ad)) )
    1.96              return 0;
    1.97      }
    1.98  
    1.99 @@ -1441,7 +1452,8 @@ static int mod_l1_entry(l1_pgentry_t *pl
   1.100  static int mod_l2_entry(l2_pgentry_t *pl2e, 
   1.101                          l2_pgentry_t nl2e, 
   1.102                          unsigned long pfn,
   1.103 -                        unsigned long type)
   1.104 +                        unsigned long type,
   1.105 +                        int preserve_ad)
   1.106  {
   1.107      l2_pgentry_t ol2e;
   1.108      struct vcpu *curr = current;
   1.109 @@ -1469,18 +1481,20 @@ static int mod_l2_entry(l2_pgentry_t *pl
   1.110  
   1.111          /* Fast path for identical mapping and presence. */
   1.112          if ( !l2e_has_changed(ol2e, nl2e, _PAGE_PRESENT))
   1.113 -            return UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr);
   1.114 +            return UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr, preserve_ad);
   1.115  
   1.116          if ( unlikely(!get_page_from_l2e(nl2e, pfn, d)) )
   1.117              return 0;
   1.118  
   1.119 -        if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr)) )
   1.120 +        if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr,
   1.121 +                                    preserve_ad)) )
   1.122          {
   1.123              put_page_from_l2e(nl2e, pfn);
   1.124              return 0;
   1.125          }
   1.126      }
   1.127 -    else if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr)) )
   1.128 +    else if ( unlikely(!UPDATE_ENTRY(l2, pl2e, ol2e, nl2e, pfn, curr,
   1.129 +                                     preserve_ad)) )
   1.130      {
   1.131          return 0;
   1.132      }
   1.133 @@ -1494,7 +1508,8 @@ static int mod_l2_entry(l2_pgentry_t *pl
   1.134  /* Update the L3 entry at pl3e to new value nl3e. pl3e is within frame pfn. */
   1.135  static int mod_l3_entry(l3_pgentry_t *pl3e, 
   1.136                          l3_pgentry_t nl3e, 
   1.137 -                        unsigned long pfn)
   1.138 +                        unsigned long pfn,
   1.139 +                        int preserve_ad)
   1.140  {
   1.141      l3_pgentry_t ol3e;
   1.142      struct vcpu *curr = current;
   1.143 @@ -1532,18 +1547,20 @@ static int mod_l3_entry(l3_pgentry_t *pl
   1.144  
   1.145          /* Fast path for identical mapping and presence. */
   1.146          if (!l3e_has_changed(ol3e, nl3e, _PAGE_PRESENT))
   1.147 -            return UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr);
   1.148 +            return UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr, preserve_ad);
   1.149  
   1.150          if ( unlikely(!get_page_from_l3e(nl3e, pfn, d)) )
   1.151              return 0;
   1.152  
   1.153 -        if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr)) )
   1.154 +        if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr,
   1.155 +                                    preserve_ad)) )
   1.156          {
   1.157              put_page_from_l3e(nl3e, pfn);
   1.158              return 0;
   1.159          }
   1.160      }
   1.161 -    else if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr)) )
   1.162 +    else if ( unlikely(!UPDATE_ENTRY(l3, pl3e, ol3e, nl3e, pfn, curr,
   1.163 +                                     preserve_ad)) )
   1.164      {
   1.165          return 0;
   1.166      }
   1.167 @@ -1564,7 +1581,8 @@ static int mod_l3_entry(l3_pgentry_t *pl
   1.168  /* Update the L4 entry at pl4e to new value nl4e. pl4e is within frame pfn. */
   1.169  static int mod_l4_entry(l4_pgentry_t *pl4e, 
   1.170                          l4_pgentry_t nl4e, 
   1.171 -                        unsigned long pfn)
   1.172 +                        unsigned long pfn,
   1.173 +                        int preserve_ad)
   1.174  {
   1.175      struct vcpu *curr = current;
   1.176      struct domain *d = curr->domain;
   1.177 @@ -1592,18 +1610,20 @@ static int mod_l4_entry(l4_pgentry_t *pl
   1.178  
   1.179          /* Fast path for identical mapping and presence. */
   1.180          if (!l4e_has_changed(ol4e, nl4e, _PAGE_PRESENT))
   1.181 -            return UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr);
   1.182 +            return UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr, preserve_ad);
   1.183  
   1.184          if ( unlikely(!get_page_from_l4e(nl4e, pfn, d)) )
   1.185              return 0;
   1.186  
   1.187 -        if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr)) )
   1.188 +        if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr,
   1.189 +                                    preserve_ad)) )
   1.190          {
   1.191              put_page_from_l4e(nl4e, pfn);
   1.192              return 0;
   1.193          }
   1.194      }
   1.195 -    else if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr)) )
   1.196 +    else if ( unlikely(!UPDATE_ENTRY(l4, pl4e, ol4e, nl4e, pfn, curr,
   1.197 +                                     preserve_ad)) )
   1.198      {
   1.199          return 0;
   1.200      }
   1.201 @@ -1946,7 +1966,7 @@ int new_guest_cr3(unsigned long mfn)
   1.202                      l4e_from_pfn(
   1.203                          mfn,
   1.204                          (_PAGE_PRESENT|_PAGE_RW|_PAGE_USER|_PAGE_ACCESSED)),
   1.205 -                    pagetable_get_pfn(v->arch.guest_table));
   1.206 +                    pagetable_get_pfn(v->arch.guest_table), 0);
   1.207          if ( unlikely(!okay) )
   1.208          {
   1.209              MEM_LOG("Error while installing new compat baseptr %lx", mfn);
   1.210 @@ -2458,13 +2478,16 @@ int do_mmu_update(
   1.211          {
   1.212              /*
   1.213               * MMU_NORMAL_PT_UPDATE: Normal update to any level of page table.
   1.214 +             * MMU_UPDATE_PT_PRESERVE_AD: As above but also preserve (OR)
   1.215 +             * current A/D bits.
   1.216               */
   1.217          case MMU_NORMAL_PT_UPDATE:
   1.218 -
   1.219 +        case MMU_PT_UPDATE_PRESERVE_AD:
   1.220              rc = xsm_mmu_normal_update(d, req.val);
   1.221              if ( rc )
   1.222                  break;
   1.223  
   1.224 +            req.ptr -= cmd;
   1.225              gmfn = req.ptr >> PAGE_SHIFT;
   1.226              mfn = gmfn_to_mfn(d, gmfn);
   1.227  
   1.228 @@ -2501,20 +2524,23 @@ int do_mmu_update(
   1.229                  case PGT_l1_page_table:
   1.230                  {
   1.231                      l1_pgentry_t l1e = l1e_from_intpte(req.val);
   1.232 -                    okay = mod_l1_entry(va, l1e, mfn);
   1.233 +                    okay = mod_l1_entry(va, l1e, mfn,
   1.234 +                                        cmd == MMU_PT_UPDATE_PRESERVE_AD);
   1.235                  }
   1.236                  break;
   1.237                  case PGT_l2_page_table:
   1.238                  {
   1.239                      l2_pgentry_t l2e = l2e_from_intpte(req.val);
   1.240 -                    okay = mod_l2_entry(va, l2e, mfn, type_info);
   1.241 +                    okay = mod_l2_entry(va, l2e, mfn, type_info,
   1.242 +                                        cmd == MMU_PT_UPDATE_PRESERVE_AD);
   1.243                  }
   1.244                  break;
   1.245  #if CONFIG_PAGING_LEVELS >= 3
   1.246                  case PGT_l3_page_table:
   1.247                  {
   1.248                      l3_pgentry_t l3e = l3e_from_intpte(req.val);
   1.249 -                    okay = mod_l3_entry(va, l3e, mfn);
   1.250 +                    okay = mod_l3_entry(va, l3e, mfn,
   1.251 +                                        cmd == MMU_PT_UPDATE_PRESERVE_AD);
   1.252                  }
   1.253                  break;
   1.254  #endif
   1.255 @@ -2522,7 +2548,8 @@ int do_mmu_update(
   1.256                  case PGT_l4_page_table:
   1.257                  {
   1.258                      l4_pgentry_t l4e = l4e_from_intpte(req.val);
   1.259 -                    okay = mod_l4_entry(va, l4e, mfn);
   1.260 +                    okay = mod_l4_entry(va, l4e, mfn,
   1.261 +                                        cmd == MMU_PT_UPDATE_PRESERVE_AD);
   1.262                  }
   1.263                  break;
   1.264  #endif
   1.265 @@ -2652,7 +2679,7 @@ static int create_grant_pte_mapping(
   1.266      }
   1.267  
   1.268      ol1e = *(l1_pgentry_t *)va;
   1.269 -    if ( !UPDATE_ENTRY(l1, (l1_pgentry_t *)va, ol1e, nl1e, mfn, v) )
   1.270 +    if ( !UPDATE_ENTRY(l1, (l1_pgentry_t *)va, ol1e, nl1e, mfn, v, 0) )
   1.271      {
   1.272          put_page_type(page);
   1.273          rc = GNTST_general_error;
   1.274 @@ -2720,9 +2747,11 @@ static int destroy_grant_pte_mapping(
   1.275      }
   1.276  
   1.277      /* Delete pagetable entry. */
   1.278 -    if ( unlikely(!UPDATE_ENTRY(l1, 
   1.279 -                      (l1_pgentry_t *)va, ol1e, l1e_empty(), mfn, 
   1.280 -                      d->vcpu[0] /* Change if we go to per-vcpu shadows. */)) )
   1.281 +    if ( unlikely(!UPDATE_ENTRY
   1.282 +                  (l1, 
   1.283 +                   (l1_pgentry_t *)va, ol1e, l1e_empty(), mfn, 
   1.284 +                   d->vcpu[0] /* Change if we go to per-vcpu shadows. */,
   1.285 +                   0)) )
   1.286      {
   1.287          MEM_LOG("Cannot delete PTE entry at %p", va);
   1.288          put_page_type(page);
   1.289 @@ -2758,7 +2787,7 @@ static int create_grant_va_mapping(
   1.290          return GNTST_general_error;
   1.291      }
   1.292      ol1e = *pl1e;
   1.293 -    okay = UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v);
   1.294 +    okay = UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v, 0);
   1.295      guest_unmap_l1e(v, pl1e);
   1.296      pl1e = NULL;
   1.297  
   1.298 @@ -2796,7 +2825,7 @@ static int replace_grant_va_mapping(
   1.299      }
   1.300  
   1.301      /* Delete pagetable entry. */
   1.302 -    if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v)) )
   1.303 +    if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, gl1mfn, v, 0)) )
   1.304      {
   1.305          MEM_LOG("Cannot delete PTE entry at %p", (unsigned long *)pl1e);
   1.306          rc = GNTST_general_error;
   1.307 @@ -2860,7 +2889,8 @@ int replace_grant_host_mapping(
   1.308      }
   1.309      ol1e = *pl1e;
   1.310  
   1.311 -    if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(), gl1mfn, curr)) )
   1.312 +    if ( unlikely(!UPDATE_ENTRY(l1, pl1e, ol1e, l1e_empty(),
   1.313 +                                gl1mfn, curr, 0)) )
   1.314      {
   1.315          MEM_LOG("Cannot delete PTE entry at %p", (unsigned long *)pl1e);
   1.316          guest_unmap_l1e(curr, pl1e);
   1.317 @@ -2948,7 +2978,7 @@ int do_update_va_mapping(unsigned long v
   1.318  
   1.319      pl1e = guest_map_l1e(v, va, &gl1mfn);
   1.320  
   1.321 -    if ( unlikely(!pl1e || !mod_l1_entry(pl1e, val, gl1mfn)) )
   1.322 +    if ( unlikely(!pl1e || !mod_l1_entry(pl1e, val, gl1mfn, 0)) )
   1.323          rc = -EINVAL;
   1.324  
   1.325      if ( pl1e )
   1.326 @@ -3517,7 +3547,7 @@ static int ptwr_emulated_update(
   1.327      else
   1.328      {
   1.329          ol1e = *pl1e;
   1.330 -        if ( !UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, mfn, v) )
   1.331 +        if ( !UPDATE_ENTRY(l1, pl1e, ol1e, nl1e, mfn, v, 0) )
   1.332              BUG();
   1.333      }
   1.334  
     2.1 --- a/xen/include/public/xen.h	Tue Jan 15 14:27:15 2008 +0000
     2.2 +++ b/xen/include/public/xen.h	Tue Jan 15 14:32:15 2008 +0000
     2.3 @@ -168,9 +168,14 @@
     2.4   * ptr[:2]  -- Machine address within the frame whose mapping to modify.
     2.5   *             The frame must belong to the FD, if one is specified.
     2.6   * val      -- Value to write into the mapping entry.
     2.7 + * 
     2.8 + * ptr[1:0] == MMU_PT_UPDATE_PRESERVE_AD:
     2.9 + * As MMU_NORMAL_PT_UPDATE above, but A/D bits currently in the PTE are ORed
    2.10 + * with those in @val.
    2.11   */
    2.12 -#define MMU_NORMAL_PT_UPDATE     0 /* checked '*ptr = val'. ptr is MA.       */
    2.13 -#define MMU_MACHPHYS_UPDATE      1 /* ptr = MA of frame to modify entry for  */
    2.14 +#define MMU_NORMAL_PT_UPDATE      0 /* checked '*ptr = val'. ptr is MA.      */
    2.15 +#define MMU_MACHPHYS_UPDATE       1 /* ptr = MA of frame to modify entry for */
    2.16 +#define MMU_PT_UPDATE_PRESERVE_AD 2 /* atomically: *ptr = val | (*ptr&(A|D)) */
    2.17  
    2.18  /*
    2.19   * MMU EXTENDED OPERATIONS