diff options
author | Jan Beulich <jbeulich@suse.com> | 2013-07-18 10:05:14 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2013-07-18 10:05:14 +0200 |
commit | e36e07bc9b0be0d899d4dd0ea675f6c225dafe5c (patch) | |
tree | 83149dec311543a053c445db196073824996ac8d /xen/arch/x86/mm.c | |
parent | 915a59f25c5eddd86bc2cae6389d0ed2ab87e69e (diff) | |
download | xen-e36e07bc9b0be0d899d4dd0ea675f6c225dafe5c.tar.gz xen-e36e07bc9b0be0d899d4dd0ea675f6c225dafe5c.tar.bz2 xen-e36e07bc9b0be0d899d4dd0ea675f6c225dafe5c.zip |
x86: fix cache flushing condition in map_pages_to_xen()
This fixes yet another shortcoming of the function (exposed by 8bfaa2c2
["x86: add locking to map_pages_to_xen()"]'s adjustment to
msix_put_fixmap()): It must not flush caches when transitioning to a
non-present mapping. Doing so causes the CLFLUSH to fault, if used in
favor of WBINVD.
To help code readability, factor out the whole flush flags updating
in map_pages_to_xen() into a helper macro.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Tested-by: Sander Eikelenboom <linux@eikelenboom.it>
Acked-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/arch/x86/mm.c')
-rw-r--r-- | xen/arch/x86/mm.c | 56 |
1 files changed, 20 insertions, 36 deletions
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c index 286e903182..c00841cd84 100644 --- a/xen/arch/x86/mm.c +++ b/xen/arch/x86/mm.c @@ -5441,6 +5441,15 @@ int map_pages_to_xen( l1_pgentry_t *pl1e, ol1e; unsigned int i; +#define flush_flags(oldf) do { \ + unsigned int o_ = (oldf); \ + if ( (o_) & _PAGE_GLOBAL ) \ + flush_flags |= FLUSH_TLB_GLOBAL; \ + if ( (flags & _PAGE_PRESENT) && \ + (((o_) ^ flags) & PAGE_CACHE_ATTRS) ) \ + flush_flags |= FLUSH_CACHE; \ +} while (0) + while ( nr_mfns != 0 ) { l3_pgentry_t ol3e, *pl3e = virt_to_xen_l3e(virt); @@ -5465,11 +5474,7 @@ int map_pages_to_xen( if ( l3e_get_flags(ol3e) & _PAGE_PSE ) { - if ( l3e_get_flags(ol3e) & _PAGE_GLOBAL ) - flush_flags |= FLUSH_TLB_GLOBAL; - if ( (lNf_to_l1f(l3e_get_flags(ol3e)) ^ flags) & - PAGE_CACHE_ATTRS ) - flush_flags |= FLUSH_CACHE; + flush_flags(lNf_to_l1f(l3e_get_flags(ol3e))); flush_area(virt, flush_flags); } else @@ -5481,27 +5486,14 @@ int map_pages_to_xen( if ( !(l2e_get_flags(ol2e) & _PAGE_PRESENT) ) continue; if ( l2e_get_flags(ol2e) & _PAGE_PSE ) - { - if ( l2e_get_flags(ol2e) & _PAGE_GLOBAL ) - flush_flags |= FLUSH_TLB_GLOBAL; - if ( (lNf_to_l1f(l2e_get_flags(ol2e)) ^ flags) & - PAGE_CACHE_ATTRS ) - flush_flags |= FLUSH_CACHE; - } + flush_flags(lNf_to_l1f(l2e_get_flags(ol2e))); else { unsigned int j; pl1e = l2e_to_l1e(ol2e); for ( j = 0; j < L1_PAGETABLE_ENTRIES; j++ ) - { - ol1e = pl1e[j]; - if ( l1e_get_flags(ol1e) & _PAGE_GLOBAL ) - flush_flags |= FLUSH_TLB_GLOBAL; - if ( (l1e_get_flags(ol1e) ^ flags) & - PAGE_CACHE_ATTRS ) - flush_flags |= FLUSH_CACHE; - } + flush_flags(l1e_get_flags(pl1e[j])); } } flush_area(virt, flush_flags); @@ -5595,24 +5587,14 @@ int map_pages_to_xen( if ( l2e_get_flags(ol2e) & _PAGE_PSE ) { - if ( l2e_get_flags(ol2e) & _PAGE_GLOBAL ) - flush_flags |= FLUSH_TLB_GLOBAL; - if ( (lNf_to_l1f(l2e_get_flags(ol2e)) ^ flags) & - PAGE_CACHE_ATTRS ) - flush_flags |= FLUSH_CACHE; + flush_flags(lNf_to_l1f(l2e_get_flags(ol2e))); flush_area(virt, flush_flags); } else { pl1e = l2e_to_l1e(ol2e); for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++ ) - { - if ( l1e_get_flags(pl1e[i]) & _PAGE_GLOBAL ) - flush_flags |= FLUSH_TLB_GLOBAL; - if ( (l1e_get_flags(pl1e[i]) ^ flags) & - PAGE_CACHE_ATTRS ) - flush_flags |= FLUSH_CACHE; - } + flush_flags(l1e_get_flags(pl1e[i])); flush_area(virt, flush_flags); free_xen_pagetable(pl1e); } @@ -5687,10 +5669,8 @@ int map_pages_to_xen( if ( (l1e_get_flags(ol1e) & _PAGE_PRESENT) ) { unsigned int flush_flags = FLUSH_TLB | FLUSH_ORDER(0); - if ( l1e_get_flags(ol1e) & _PAGE_GLOBAL ) - flush_flags |= FLUSH_TLB_GLOBAL; - if ( (l1e_get_flags(ol1e) ^ flags) & PAGE_CACHE_ATTRS ) - flush_flags |= FLUSH_CACHE; + + flush_flags(l1e_get_flags(ol1e)); flush_area(virt, flush_flags); } @@ -5766,6 +5746,8 @@ int map_pages_to_xen( } } +#undef flush_flags + return 0; } @@ -5908,6 +5890,8 @@ void destroy_xen_mappings(unsigned long s, unsigned long e) flush_area(NULL, FLUSH_TLB_GLOBAL); } +#undef flush_area + void __set_fixmap( enum fixed_addresses idx, unsigned long mfn, unsigned long flags) { |