ia64/xen-unstable
changeset 10481:2a99292b1a8a
[XEN][PAE] Stores to PTEs in PAE mode use CMPXCHG to ensure atomicity.
Signed-off-by: Keir Fraser <keir@xensource.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
author | kfraser@dhcp93.uk.xensource.com |
---|---|
date | Mon Jun 19 14:44:34 2006 +0100 (2006-06-19) |
parents | a27f56a0ff43 |
children | 0991ed8e4ae5 |
files | xen/arch/x86/mm.c |
line diff
1.1 --- a/xen/arch/x86/mm.c Mon Jun 19 14:03:04 2006 +0100 1.2 +++ b/xen/arch/x86/mm.c Mon Jun 19 14:44:34 2006 +0100 1.3 @@ -108,14 +108,23 @@ 1.4 #include <public/memory.h> 1.5 1.6 #ifdef VERBOSE 1.7 -#define MEM_LOG(_f, _a...) \ 1.8 - printk("DOM%u: (file=mm.c, line=%d) " _f "\n", \ 1.9 +#define MEM_LOG(_f, _a...) \ 1.10 + printk("DOM%u: (file=mm.c, line=%d) " _f "\n", \ 1.11 current->domain->domain_id , __LINE__ , ## _a ) 1.12 #else 1.13 #define MEM_LOG(_f, _a...) ((void)0) 1.14 #endif 1.15 1.16 /* 1.17 + * PTE updates can be done with ordinary writes except: 1.18 + * 1. Debug builds get extra checking by using CMPXCHG[8B]. 1.19 + * 2. PAE builds perform an atomic 8-byte store with CMPXCHG8B. 1.20 + */ 1.21 +#if !defined(NDEBUG) || defined(CONFIG_X86_PAE) 1.22 +#define PTE_UPDATE_WITH_CMPXCHG 1.23 +#endif 1.24 + 1.25 +/* 1.26 * Both do_mmuext_op() and do_mmu_update(): 1.27 * We steal the m.s.b. of the @count parameter to indicate whether this 1.28 * invocation of do_mmu_update() is resuming a previously preempted call. 1.29 @@ -1173,16 +1182,27 @@ static inline int update_l1e(l1_pgentry_ 1.30 intpte_t o = l1e_get_intpte(ol1e); 1.31 intpte_t n = l1e_get_intpte(nl1e); 1.32 1.33 - if ( unlikely(cmpxchg_user(pl1e, o, n) != 0) || 1.34 - unlikely(o != l1e_get_intpte(ol1e)) ) 1.35 + for ( ; ; ) 1.36 { 1.37 - MEM_LOG("Failed to update %" PRIpte " -> %" PRIpte 1.38 - ": saw %" PRIpte, 1.39 - l1e_get_intpte(ol1e), 1.40 - l1e_get_intpte(nl1e), 1.41 - o); 1.42 - return 0; 1.43 + if ( unlikely(cmpxchg_user(pl1e, o, n) != 0) ) 1.44 + { 1.45 + MEM_LOG("Failed to update %" PRIpte " -> %" PRIpte 1.46 + ": saw %" PRIpte, 1.47 + l1e_get_intpte(ol1e), 1.48 + l1e_get_intpte(nl1e), 1.49 + o); 1.50 + return 0; 1.51 + } 1.52 + 1.53 + if ( o == l1e_get_intpte(ol1e) ) 1.54 + break; 1.55 + 1.56 + /* Allowed to change in Accessed/Dirty flags only. */ 1.57 + BUG_ON((o ^ l1e_get_intpte(ol1e)) & 1.58 + ~(int)(_PAGE_ACCESSED|_PAGE_DIRTY)); 1.59 + ol1e = l1e_from_intpte(o); 1.60 } 1.61 + 1.62 return 1; 1.63 #endif 1.64 } 1.65 @@ -1235,17 +1255,20 @@ static int mod_l1_entry(l1_pgentry_t *pl 1.66 #ifndef PTE_UPDATE_WITH_CMPXCHG 1.67 #define UPDATE_ENTRY(_t,_p,_o,_n) ({ (*(_p) = (_n)); 1; }) 1.68 #else 1.69 -#define UPDATE_ENTRY(_t,_p,_o,_n) ({ \ 1.70 - intpte_t __o = cmpxchg((intpte_t *)(_p), \ 1.71 - _t ## e_get_intpte(_o), \ 1.72 - _t ## e_get_intpte(_n)); \ 1.73 - if ( __o != _t ## e_get_intpte(_o) ) \ 1.74 - MEM_LOG("Failed to update %" PRIpte " -> %" PRIpte \ 1.75 - ": saw %" PRIpte "", \ 1.76 - (_t ## e_get_intpte(_o)), \ 1.77 - (_t ## e_get_intpte(_n)), \ 1.78 - (__o)); \ 1.79 - (__o == _t ## e_get_intpte(_o)); }) 1.80 +#define UPDATE_ENTRY(_t,_p,_o,_n) ({ \ 1.81 + for ( ; ; ) \ 1.82 + { \ 1.83 + intpte_t __o = cmpxchg((intpte_t *)(_p), \ 1.84 + _t ## e_get_intpte(_o), \ 1.85 + _t ## e_get_intpte(_n)); \ 1.86 + if ( __o == _t ## e_get_intpte(_o) ) \ 1.87 + break; \ 1.88 + /* Allowed to change in Accessed/Dirty flags only. */ \ 1.89 + BUG_ON((__o ^ _t ## e_get_intpte(_o)) & \ 1.90 + ~(int)(_PAGE_ACCESSED|_PAGE_DIRTY)); \ 1.91 + _o = _t ## e_from_intpte(__o); \ 1.92 + } \ 1.93 + 1; }) 1.94 #endif 1.95 1.96 /* Update the L2 entry at pl2e to new value nl2e. pl2e is within frame pfn. */ 1.97 @@ -2494,7 +2517,7 @@ static int destroy_grant_pte_mapping( 1.98 } 1.99 1.100 /* Delete pagetable entry. */ 1.101 - if ( unlikely(__put_user(0, (intpte_t *)va))) 1.102 + if ( unlikely(!update_l1e((l1_pgentry_t *)va, ol1e, l1e_empty())) ) 1.103 { 1.104 MEM_LOG("Cannot delete PTE entry at %p", va); 1.105 put_page_type(page); 1.106 @@ -2574,7 +2597,7 @@ static int destroy_grant_va_mapping( 1.107 } 1.108 1.109 /* Delete pagetable entry. */ 1.110 - if ( unlikely(__put_user(0, &pl1e->l1)) ) 1.111 + if ( unlikely(!update_l1e(pl1e, ol1e, l1e_empty())) ) 1.112 { 1.113 MEM_LOG("Cannot delete PTE entry at %p", (unsigned long *)pl1e); 1.114 return GNTST_general_error; 1.115 @@ -3424,8 +3447,9 @@ static int ptwr_emulated_update( 1.116 } 1.117 else 1.118 { 1.119 - ol1e = *pl1e; 1.120 - *pl1e = nl1e; 1.121 + ol1e = *pl1e; 1.122 + if ( !update_l1e(pl1e, ol1e, nl1e) ) 1.123 + BUG(); 1.124 } 1.125 unmap_domain_page(pl1e); 1.126