162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/arm/mm/flush.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1995-2002 Russell King 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/module.h> 862306a36Sopenharmony_ci#include <linux/mm.h> 962306a36Sopenharmony_ci#include <linux/pagemap.h> 1062306a36Sopenharmony_ci#include <linux/highmem.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <asm/cacheflush.h> 1362306a36Sopenharmony_ci#include <asm/cachetype.h> 1462306a36Sopenharmony_ci#include <asm/highmem.h> 1562306a36Sopenharmony_ci#include <asm/smp_plat.h> 1662306a36Sopenharmony_ci#include <asm/tlbflush.h> 1762306a36Sopenharmony_ci#include <linux/hugetlb.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "mm.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#ifdef CONFIG_ARM_HEAVY_MB 2262306a36Sopenharmony_civoid (*soc_mb)(void); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_civoid arm_heavy_mb(void) 2562306a36Sopenharmony_ci{ 2662306a36Sopenharmony_ci#ifdef CONFIG_OUTER_CACHE_SYNC 2762306a36Sopenharmony_ci if (outer_cache.sync) 2862306a36Sopenharmony_ci outer_cache.sync(); 2962306a36Sopenharmony_ci#endif 3062306a36Sopenharmony_ci if (soc_mb) 3162306a36Sopenharmony_ci soc_mb(); 3262306a36Sopenharmony_ci} 3362306a36Sopenharmony_ciEXPORT_SYMBOL(arm_heavy_mb); 3462306a36Sopenharmony_ci#endif 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#ifdef CONFIG_CPU_CACHE_VIPT 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic void flush_pfn_alias(unsigned long pfn, unsigned long vaddr) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci unsigned long to = FLUSH_ALIAS_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT); 4162306a36Sopenharmony_ci const int zero = 0; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci set_top_pte(to, pfn_pte(pfn, PAGE_KERNEL)); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci asm( "mcrr p15, 0, %1, %0, c14\n" 4662306a36Sopenharmony_ci " mcr p15, 0, %2, c7, c10, 4" 4762306a36Sopenharmony_ci : 4862306a36Sopenharmony_ci : "r" (to), "r" (to + PAGE_SIZE - 1), "r" (zero) 4962306a36Sopenharmony_ci : "cc"); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic void flush_icache_alias(unsigned long pfn, unsigned long vaddr, unsigned long len) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci unsigned long va = FLUSH_ALIAS_START + (CACHE_COLOUR(vaddr) << PAGE_SHIFT); 5562306a36Sopenharmony_ci unsigned long offset = vaddr & (PAGE_SIZE - 1); 5662306a36Sopenharmony_ci unsigned long to; 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_ci set_top_pte(va, pfn_pte(pfn, PAGE_KERNEL)); 5962306a36Sopenharmony_ci to = va + offset; 6062306a36Sopenharmony_ci flush_icache_range(to, to + len); 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_civoid flush_cache_mm(struct mm_struct *mm) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci if (cache_is_vivt()) { 6662306a36Sopenharmony_ci vivt_flush_cache_mm(mm); 6762306a36Sopenharmony_ci return; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci if (cache_is_vipt_aliasing()) { 7162306a36Sopenharmony_ci asm( "mcr p15, 0, %0, c7, c14, 0\n" 7262306a36Sopenharmony_ci " mcr p15, 0, %0, c7, c10, 4" 7362306a36Sopenharmony_ci : 7462306a36Sopenharmony_ci : "r" (0) 7562306a36Sopenharmony_ci : "cc"); 7662306a36Sopenharmony_ci } 7762306a36Sopenharmony_ci} 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_civoid flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci if (cache_is_vivt()) { 8262306a36Sopenharmony_ci vivt_flush_cache_range(vma, start, end); 8362306a36Sopenharmony_ci return; 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (cache_is_vipt_aliasing()) { 8762306a36Sopenharmony_ci asm( "mcr p15, 0, %0, c7, c14, 0\n" 8862306a36Sopenharmony_ci " mcr p15, 0, %0, c7, c10, 4" 8962306a36Sopenharmony_ci : 9062306a36Sopenharmony_ci : "r" (0) 9162306a36Sopenharmony_ci : "cc"); 9262306a36Sopenharmony_ci } 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (vma->vm_flags & VM_EXEC) 9562306a36Sopenharmony_ci __flush_icache_all(); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_civoid flush_cache_pages(struct vm_area_struct *vma, unsigned long user_addr, unsigned long pfn, unsigned int nr) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci if (cache_is_vivt()) { 10162306a36Sopenharmony_ci vivt_flush_cache_pages(vma, user_addr, pfn, nr); 10262306a36Sopenharmony_ci return; 10362306a36Sopenharmony_ci } 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci if (cache_is_vipt_aliasing()) { 10662306a36Sopenharmony_ci flush_pfn_alias(pfn, user_addr); 10762306a36Sopenharmony_ci __flush_icache_all(); 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci if (vma->vm_flags & VM_EXEC && icache_is_vivt_asid_tagged()) 11162306a36Sopenharmony_ci __flush_icache_all(); 11262306a36Sopenharmony_ci} 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci#else 11562306a36Sopenharmony_ci#define flush_pfn_alias(pfn,vaddr) do { } while (0) 11662306a36Sopenharmony_ci#define flush_icache_alias(pfn,vaddr,len) do { } while (0) 11762306a36Sopenharmony_ci#endif 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci#define FLAG_PA_IS_EXEC 1 12062306a36Sopenharmony_ci#define FLAG_PA_CORE_IN_MM 2 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_cistatic void flush_ptrace_access_other(void *args) 12362306a36Sopenharmony_ci{ 12462306a36Sopenharmony_ci __flush_icache_all(); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_cistatic inline 12862306a36Sopenharmony_civoid __flush_ptrace_access(struct page *page, unsigned long uaddr, void *kaddr, 12962306a36Sopenharmony_ci unsigned long len, unsigned int flags) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci if (cache_is_vivt()) { 13262306a36Sopenharmony_ci if (flags & FLAG_PA_CORE_IN_MM) { 13362306a36Sopenharmony_ci unsigned long addr = (unsigned long)kaddr; 13462306a36Sopenharmony_ci __cpuc_coherent_kern_range(addr, addr + len); 13562306a36Sopenharmony_ci } 13662306a36Sopenharmony_ci return; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (cache_is_vipt_aliasing()) { 14062306a36Sopenharmony_ci flush_pfn_alias(page_to_pfn(page), uaddr); 14162306a36Sopenharmony_ci __flush_icache_all(); 14262306a36Sopenharmony_ci return; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci /* VIPT non-aliasing D-cache */ 14662306a36Sopenharmony_ci if (flags & FLAG_PA_IS_EXEC) { 14762306a36Sopenharmony_ci unsigned long addr = (unsigned long)kaddr; 14862306a36Sopenharmony_ci if (icache_is_vipt_aliasing()) 14962306a36Sopenharmony_ci flush_icache_alias(page_to_pfn(page), uaddr, len); 15062306a36Sopenharmony_ci else 15162306a36Sopenharmony_ci __cpuc_coherent_kern_range(addr, addr + len); 15262306a36Sopenharmony_ci if (cache_ops_need_broadcast()) 15362306a36Sopenharmony_ci smp_call_function(flush_ptrace_access_other, 15462306a36Sopenharmony_ci NULL, 1); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cistatic 15962306a36Sopenharmony_civoid flush_ptrace_access(struct vm_area_struct *vma, struct page *page, 16062306a36Sopenharmony_ci unsigned long uaddr, void *kaddr, unsigned long len) 16162306a36Sopenharmony_ci{ 16262306a36Sopenharmony_ci unsigned int flags = 0; 16362306a36Sopenharmony_ci if (cpumask_test_cpu(smp_processor_id(), mm_cpumask(vma->vm_mm))) 16462306a36Sopenharmony_ci flags |= FLAG_PA_CORE_IN_MM; 16562306a36Sopenharmony_ci if (vma->vm_flags & VM_EXEC) 16662306a36Sopenharmony_ci flags |= FLAG_PA_IS_EXEC; 16762306a36Sopenharmony_ci __flush_ptrace_access(page, uaddr, kaddr, len, flags); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_civoid flush_uprobe_xol_access(struct page *page, unsigned long uaddr, 17162306a36Sopenharmony_ci void *kaddr, unsigned long len) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci unsigned int flags = FLAG_PA_CORE_IN_MM|FLAG_PA_IS_EXEC; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci __flush_ptrace_access(page, uaddr, kaddr, len, flags); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci/* 17962306a36Sopenharmony_ci * Copy user data from/to a page which is mapped into a different 18062306a36Sopenharmony_ci * processes address space. Really, we want to allow our "user 18162306a36Sopenharmony_ci * space" model to handle this. 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * Note that this code needs to run on the current CPU. 18462306a36Sopenharmony_ci */ 18562306a36Sopenharmony_civoid copy_to_user_page(struct vm_area_struct *vma, struct page *page, 18662306a36Sopenharmony_ci unsigned long uaddr, void *dst, const void *src, 18762306a36Sopenharmony_ci unsigned long len) 18862306a36Sopenharmony_ci{ 18962306a36Sopenharmony_ci#ifdef CONFIG_SMP 19062306a36Sopenharmony_ci preempt_disable(); 19162306a36Sopenharmony_ci#endif 19262306a36Sopenharmony_ci memcpy(dst, src, len); 19362306a36Sopenharmony_ci flush_ptrace_access(vma, page, uaddr, dst, len); 19462306a36Sopenharmony_ci#ifdef CONFIG_SMP 19562306a36Sopenharmony_ci preempt_enable(); 19662306a36Sopenharmony_ci#endif 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_civoid __flush_dcache_folio(struct address_space *mapping, struct folio *folio) 20062306a36Sopenharmony_ci{ 20162306a36Sopenharmony_ci /* 20262306a36Sopenharmony_ci * Writeback any data associated with the kernel mapping of this 20362306a36Sopenharmony_ci * page. This ensures that data in the physical page is mutually 20462306a36Sopenharmony_ci * coherent with the kernels mapping. 20562306a36Sopenharmony_ci */ 20662306a36Sopenharmony_ci if (!folio_test_highmem(folio)) { 20762306a36Sopenharmony_ci __cpuc_flush_dcache_area(folio_address(folio), 20862306a36Sopenharmony_ci folio_size(folio)); 20962306a36Sopenharmony_ci } else { 21062306a36Sopenharmony_ci unsigned long i; 21162306a36Sopenharmony_ci if (cache_is_vipt_nonaliasing()) { 21262306a36Sopenharmony_ci for (i = 0; i < folio_nr_pages(folio); i++) { 21362306a36Sopenharmony_ci void *addr = kmap_local_folio(folio, 21462306a36Sopenharmony_ci i * PAGE_SIZE); 21562306a36Sopenharmony_ci __cpuc_flush_dcache_area(addr, PAGE_SIZE); 21662306a36Sopenharmony_ci kunmap_local(addr); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci } else { 21962306a36Sopenharmony_ci for (i = 0; i < folio_nr_pages(folio); i++) { 22062306a36Sopenharmony_ci void *addr = kmap_high_get(folio_page(folio, i)); 22162306a36Sopenharmony_ci if (addr) { 22262306a36Sopenharmony_ci __cpuc_flush_dcache_area(addr, PAGE_SIZE); 22362306a36Sopenharmony_ci kunmap_high(folio_page(folio, i)); 22462306a36Sopenharmony_ci } 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* 23062306a36Sopenharmony_ci * If this is a page cache page, and we have an aliasing VIPT cache, 23162306a36Sopenharmony_ci * we only need to do one flush - which would be at the relevant 23262306a36Sopenharmony_ci * userspace colour, which is congruent with page->index. 23362306a36Sopenharmony_ci */ 23462306a36Sopenharmony_ci if (mapping && cache_is_vipt_aliasing()) 23562306a36Sopenharmony_ci flush_pfn_alias(folio_pfn(folio), folio_pos(folio)); 23662306a36Sopenharmony_ci} 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_cistatic void __flush_dcache_aliases(struct address_space *mapping, struct folio *folio) 23962306a36Sopenharmony_ci{ 24062306a36Sopenharmony_ci struct mm_struct *mm = current->active_mm; 24162306a36Sopenharmony_ci struct vm_area_struct *vma; 24262306a36Sopenharmony_ci pgoff_t pgoff, pgoff_end; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci /* 24562306a36Sopenharmony_ci * There are possible user space mappings of this page: 24662306a36Sopenharmony_ci * - VIVT cache: we need to also write back and invalidate all user 24762306a36Sopenharmony_ci * data in the current VM view associated with this page. 24862306a36Sopenharmony_ci * - aliasing VIPT: we only need to find one mapping of this page. 24962306a36Sopenharmony_ci */ 25062306a36Sopenharmony_ci pgoff = folio->index; 25162306a36Sopenharmony_ci pgoff_end = pgoff + folio_nr_pages(folio) - 1; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci flush_dcache_mmap_lock(mapping); 25462306a36Sopenharmony_ci vma_interval_tree_foreach(vma, &mapping->i_mmap, pgoff, pgoff_end) { 25562306a36Sopenharmony_ci unsigned long start, offset, pfn; 25662306a36Sopenharmony_ci unsigned int nr; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci /* 25962306a36Sopenharmony_ci * If this VMA is not in our MM, we can ignore it. 26062306a36Sopenharmony_ci */ 26162306a36Sopenharmony_ci if (vma->vm_mm != mm) 26262306a36Sopenharmony_ci continue; 26362306a36Sopenharmony_ci if (!(vma->vm_flags & VM_MAYSHARE)) 26462306a36Sopenharmony_ci continue; 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci start = vma->vm_start; 26762306a36Sopenharmony_ci pfn = folio_pfn(folio); 26862306a36Sopenharmony_ci nr = folio_nr_pages(folio); 26962306a36Sopenharmony_ci offset = pgoff - vma->vm_pgoff; 27062306a36Sopenharmony_ci if (offset > -nr) { 27162306a36Sopenharmony_ci pfn -= offset; 27262306a36Sopenharmony_ci nr += offset; 27362306a36Sopenharmony_ci } else { 27462306a36Sopenharmony_ci start += offset * PAGE_SIZE; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci if (start + nr * PAGE_SIZE > vma->vm_end) 27762306a36Sopenharmony_ci nr = (vma->vm_end - start) / PAGE_SIZE; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci flush_cache_pages(vma, start, pfn, nr); 28062306a36Sopenharmony_ci } 28162306a36Sopenharmony_ci flush_dcache_mmap_unlock(mapping); 28262306a36Sopenharmony_ci} 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 6 28562306a36Sopenharmony_civoid __sync_icache_dcache(pte_t pteval) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci unsigned long pfn; 28862306a36Sopenharmony_ci struct folio *folio; 28962306a36Sopenharmony_ci struct address_space *mapping; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci if (cache_is_vipt_nonaliasing() && !pte_exec(pteval)) 29262306a36Sopenharmony_ci /* only flush non-aliasing VIPT caches for exec mappings */ 29362306a36Sopenharmony_ci return; 29462306a36Sopenharmony_ci pfn = pte_pfn(pteval); 29562306a36Sopenharmony_ci if (!pfn_valid(pfn)) 29662306a36Sopenharmony_ci return; 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci folio = page_folio(pfn_to_page(pfn)); 29962306a36Sopenharmony_ci if (cache_is_vipt_aliasing()) 30062306a36Sopenharmony_ci mapping = folio_flush_mapping(folio); 30162306a36Sopenharmony_ci else 30262306a36Sopenharmony_ci mapping = NULL; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci if (!test_and_set_bit(PG_dcache_clean, &folio->flags)) 30562306a36Sopenharmony_ci __flush_dcache_folio(mapping, folio); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (pte_exec(pteval)) 30862306a36Sopenharmony_ci __flush_icache_all(); 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci#endif 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci/* 31362306a36Sopenharmony_ci * Ensure cache coherency between kernel mapping and userspace mapping 31462306a36Sopenharmony_ci * of this page. 31562306a36Sopenharmony_ci * 31662306a36Sopenharmony_ci * We have three cases to consider: 31762306a36Sopenharmony_ci * - VIPT non-aliasing cache: fully coherent so nothing required. 31862306a36Sopenharmony_ci * - VIVT: fully aliasing, so we need to handle every alias in our 31962306a36Sopenharmony_ci * current VM view. 32062306a36Sopenharmony_ci * - VIPT aliasing: need to handle one alias in our current VM view. 32162306a36Sopenharmony_ci * 32262306a36Sopenharmony_ci * If we need to handle aliasing: 32362306a36Sopenharmony_ci * If the page only exists in the page cache and there are no user 32462306a36Sopenharmony_ci * space mappings, we can be lazy and remember that we may have dirty 32562306a36Sopenharmony_ci * kernel cache lines for later. Otherwise, we assume we have 32662306a36Sopenharmony_ci * aliasing mappings. 32762306a36Sopenharmony_ci * 32862306a36Sopenharmony_ci * Note that we disable the lazy flush for SMP configurations where 32962306a36Sopenharmony_ci * the cache maintenance operations are not automatically broadcasted. 33062306a36Sopenharmony_ci */ 33162306a36Sopenharmony_civoid flush_dcache_folio(struct folio *folio) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct address_space *mapping; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* 33662306a36Sopenharmony_ci * The zero page is never written to, so never has any dirty 33762306a36Sopenharmony_ci * cache lines, and therefore never needs to be flushed. 33862306a36Sopenharmony_ci */ 33962306a36Sopenharmony_ci if (is_zero_pfn(folio_pfn(folio))) 34062306a36Sopenharmony_ci return; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_ci if (!cache_ops_need_broadcast() && cache_is_vipt_nonaliasing()) { 34362306a36Sopenharmony_ci if (test_bit(PG_dcache_clean, &folio->flags)) 34462306a36Sopenharmony_ci clear_bit(PG_dcache_clean, &folio->flags); 34562306a36Sopenharmony_ci return; 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci mapping = folio_flush_mapping(folio); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci if (!cache_ops_need_broadcast() && 35162306a36Sopenharmony_ci mapping && !folio_mapped(folio)) 35262306a36Sopenharmony_ci clear_bit(PG_dcache_clean, &folio->flags); 35362306a36Sopenharmony_ci else { 35462306a36Sopenharmony_ci __flush_dcache_folio(mapping, folio); 35562306a36Sopenharmony_ci if (mapping && cache_is_vivt()) 35662306a36Sopenharmony_ci __flush_dcache_aliases(mapping, folio); 35762306a36Sopenharmony_ci else if (mapping) 35862306a36Sopenharmony_ci __flush_icache_all(); 35962306a36Sopenharmony_ci set_bit(PG_dcache_clean, &folio->flags); 36062306a36Sopenharmony_ci } 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ciEXPORT_SYMBOL(flush_dcache_folio); 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_civoid flush_dcache_page(struct page *page) 36562306a36Sopenharmony_ci{ 36662306a36Sopenharmony_ci flush_dcache_folio(page_folio(page)); 36762306a36Sopenharmony_ci} 36862306a36Sopenharmony_ciEXPORT_SYMBOL(flush_dcache_page); 36962306a36Sopenharmony_ci/* 37062306a36Sopenharmony_ci * Flush an anonymous page so that users of get_user_pages() 37162306a36Sopenharmony_ci * can safely access the data. The expected sequence is: 37262306a36Sopenharmony_ci * 37362306a36Sopenharmony_ci * get_user_pages() 37462306a36Sopenharmony_ci * -> flush_anon_page 37562306a36Sopenharmony_ci * memcpy() to/from page 37662306a36Sopenharmony_ci * if written to page, flush_dcache_page() 37762306a36Sopenharmony_ci */ 37862306a36Sopenharmony_civoid __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr); 37962306a36Sopenharmony_civoid __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned long vmaddr) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci unsigned long pfn; 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci /* VIPT non-aliasing caches need do nothing */ 38462306a36Sopenharmony_ci if (cache_is_vipt_nonaliasing()) 38562306a36Sopenharmony_ci return; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci /* 38862306a36Sopenharmony_ci * Write back and invalidate userspace mapping. 38962306a36Sopenharmony_ci */ 39062306a36Sopenharmony_ci pfn = page_to_pfn(page); 39162306a36Sopenharmony_ci if (cache_is_vivt()) { 39262306a36Sopenharmony_ci flush_cache_page(vma, vmaddr, pfn); 39362306a36Sopenharmony_ci } else { 39462306a36Sopenharmony_ci /* 39562306a36Sopenharmony_ci * For aliasing VIPT, we can flush an alias of the 39662306a36Sopenharmony_ci * userspace address only. 39762306a36Sopenharmony_ci */ 39862306a36Sopenharmony_ci flush_pfn_alias(pfn, vmaddr); 39962306a36Sopenharmony_ci __flush_icache_all(); 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci /* 40362306a36Sopenharmony_ci * Invalidate kernel mapping. No data should be contained 40462306a36Sopenharmony_ci * in this mapping of the page. FIXME: this is overkill 40562306a36Sopenharmony_ci * since we actually ask for a write-back and invalidate. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_ci __cpuc_flush_dcache_area(page_address(page), PAGE_SIZE); 40862306a36Sopenharmony_ci} 409