18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Based on arch/arm/mm/flush.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1995-2002 Russell King
68c2ecf20Sopenharmony_ci * Copyright (C) 2012 ARM Ltd.
78c2ecf20Sopenharmony_ci */
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include <linux/export.h>
108c2ecf20Sopenharmony_ci#include <linux/mm.h>
118c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <asm/cacheflush.h>
148c2ecf20Sopenharmony_ci#include <asm/cache.h>
158c2ecf20Sopenharmony_ci#include <asm/tlbflush.h>
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_civoid sync_icache_aliases(void *kaddr, unsigned long len)
188c2ecf20Sopenharmony_ci{
198c2ecf20Sopenharmony_ci	unsigned long addr = (unsigned long)kaddr;
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci	if (icache_is_aliasing()) {
228c2ecf20Sopenharmony_ci		__clean_dcache_area_pou(kaddr, len);
238c2ecf20Sopenharmony_ci		__flush_icache_all();
248c2ecf20Sopenharmony_ci	} else {
258c2ecf20Sopenharmony_ci		/*
268c2ecf20Sopenharmony_ci		 * Don't issue kick_all_cpus_sync() after I-cache invalidation
278c2ecf20Sopenharmony_ci		 * for user mappings.
288c2ecf20Sopenharmony_ci		 */
298c2ecf20Sopenharmony_ci		__flush_icache_range(addr, addr + len);
308c2ecf20Sopenharmony_ci	}
318c2ecf20Sopenharmony_ci}
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic void flush_ptrace_access(struct vm_area_struct *vma, struct page *page,
348c2ecf20Sopenharmony_ci				unsigned long uaddr, void *kaddr,
358c2ecf20Sopenharmony_ci				unsigned long len)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	if (vma->vm_flags & VM_EXEC)
388c2ecf20Sopenharmony_ci		sync_icache_aliases(kaddr, len);
398c2ecf20Sopenharmony_ci}
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci/*
428c2ecf20Sopenharmony_ci * Copy user data from/to a page which is mapped into a different processes
438c2ecf20Sopenharmony_ci * address space.  Really, we want to allow our "user space" model to handle
448c2ecf20Sopenharmony_ci * this.
458c2ecf20Sopenharmony_ci */
468c2ecf20Sopenharmony_civoid copy_to_user_page(struct vm_area_struct *vma, struct page *page,
478c2ecf20Sopenharmony_ci		       unsigned long uaddr, void *dst, const void *src,
488c2ecf20Sopenharmony_ci		       unsigned long len)
498c2ecf20Sopenharmony_ci{
508c2ecf20Sopenharmony_ci	memcpy(dst, src, len);
518c2ecf20Sopenharmony_ci	flush_ptrace_access(vma, page, uaddr, dst, len);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_civoid __sync_icache_dcache(pte_t pte)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	struct page *page = pte_page(pte);
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	if (!test_bit(PG_dcache_clean, &page->flags)) {
598c2ecf20Sopenharmony_ci		sync_icache_aliases(page_address(page), page_size(page));
608c2ecf20Sopenharmony_ci		set_bit(PG_dcache_clean, &page->flags);
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci}
638c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(__sync_icache_dcache);
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci/*
668c2ecf20Sopenharmony_ci * This function is called when a page has been modified by the kernel. Mark
678c2ecf20Sopenharmony_ci * it as dirty for later flushing when mapped in user space (if executable,
688c2ecf20Sopenharmony_ci * see __sync_icache_dcache).
698c2ecf20Sopenharmony_ci */
708c2ecf20Sopenharmony_civoid flush_dcache_page(struct page *page)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	if (test_bit(PG_dcache_clean, &page->flags))
738c2ecf20Sopenharmony_ci		clear_bit(PG_dcache_clean, &page->flags);
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ciEXPORT_SYMBOL(flush_dcache_page);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci/*
788c2ecf20Sopenharmony_ci * Additional functions defined in assembly.
798c2ecf20Sopenharmony_ci */
808c2ecf20Sopenharmony_ciEXPORT_SYMBOL(__flush_icache_range);
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_HAS_PMEM_API
838c2ecf20Sopenharmony_civoid arch_wb_cache_pmem(void *addr, size_t size)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	/* Ensure order against any prior non-cacheable writes */
868c2ecf20Sopenharmony_ci	dmb(osh);
878c2ecf20Sopenharmony_ci	__clean_dcache_area_pop(addr, size);
888c2ecf20Sopenharmony_ci}
898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(arch_wb_cache_pmem);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_civoid arch_invalidate_pmem(void *addr, size_t size)
928c2ecf20Sopenharmony_ci{
938c2ecf20Sopenharmony_ci	__inval_dcache_area(addr, size);
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(arch_invalidate_pmem);
968c2ecf20Sopenharmony_ci#endif
97