Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[PARISC] prevent speculative re-read on cache flush

According to Appendix F, the TLB is the primary arbiter of speculation.
Thus, if a page has a TLB entry, it may be speculatively read into the
cache. On linux, this can cause us incoherencies because if we're about
to do a disk read, we call get_user_pages() to do the flush/invalidate
in user space, but we still potentially have the user TLB entries, and
the cache could speculate the lines back into userspace (thus causing
stale data to be used). This is fixed by purging the TLB entries before
we flush through the tmpalias space. Now, the only way the line could
be re-speculated is if the user actually tries to touch it (which is not
allowed).

Signed-off-by: James Bottomley <James.Bottomley@suse.de>

authored by

James Bottomley and committed by
James Bottomley
b7d45818 d7dd2ff1

+16 -2
+4 -1
arch/parisc/include/asm/cacheflush.h
··· 3 3 4 4 #include <linux/mm.h> 5 5 #include <linux/uaccess.h> 6 + #include <asm/tlbflush.h> 6 7 7 8 /* The usual comment is "Caches aren't brain-dead on the <architecture>". 8 9 * Unfortunately, that doesn't apply to PA-RISC. */ ··· 113 112 static inline void 114 113 flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr) 115 114 { 116 - if (PageAnon(page)) 115 + if (PageAnon(page)) { 116 + flush_tlb_page(vma, vmaddr); 117 117 flush_dcache_page_asm(page_to_phys(page), vmaddr); 118 + } 118 119 } 119 120 120 121 #ifdef CONFIG_DEBUG_RODATA
+12 -1
arch/parisc/kernel/cache.c
··· 304 304 offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT; 305 305 addr = mpnt->vm_start + offset; 306 306 307 + /* The TLB is the engine of coherence on parisc: The 308 + * CPU is entitled to speculate any page with a TLB 309 + * mapping, so here we kill the mapping then flush the 310 + * page along a special flush only alias mapping. 311 + * This guarantees that the page is no-longer in the 312 + * cache for any process and nor may it be 313 + * speculatively read in (until the user or kernel 314 + * specifically accesses it, of course) */ 315 + 316 + flush_tlb_page(mpnt, addr); 307 317 if (old_addr == 0 || (old_addr & (SHMLBA - 1)) != (addr & (SHMLBA - 1))) { 308 318 __flush_cache_page(mpnt, addr, page_to_phys(page)); 309 319 if (old_addr) 310 - printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? mpnt->vm_file->f_path.dentry->d_name.name : "(null)"); 320 + printk(KERN_ERR "INEQUIVALENT ALIASES 0x%lx and 0x%lx in file %s\n", old_addr, addr, mpnt->vm_file ? (char *)mpnt->vm_file->f_path.dentry->d_name.name : "(null)"); 311 321 old_addr = addr; 312 322 } 313 323 } ··· 509 499 { 510 500 BUG_ON(!vma->vm_mm->context); 511 501 502 + flush_tlb_page(vma, vmaddr); 512 503 __flush_cache_page(vma, vmaddr, page_to_phys(pfn_to_page(pfn))); 513 504 514 505 }