Implement the missing cacheflush() syscall. Signed-off-by: Helge Deller <deller@xxxxxx> --- arch/parisc/include/asm/assembly.h | 7 ++++ arch/parisc/include/uapi/asm/cachectl.h | 12 +++++++ arch/parisc/kernel/cache.c | 46 +++++++++++++++++++++++++ arch/parisc/kernel/syscalls/syscall.tbl | 1 + 4 files changed, 66 insertions(+) create mode 100644 arch/parisc/include/uapi/asm/cachectl.h diff --git a/arch/parisc/include/asm/assembly.h b/arch/parisc/include/asm/assembly.h index 0f0d4a496fef..286fea9b6372 100644 --- a/arch/parisc/include/asm/assembly.h +++ b/arch/parisc/include/asm/assembly.h @@ -581,6 +581,13 @@ .word (fault_addr - .), (except_addr - .) ! \ .previous +#else /* __ASSEMBLY__ */ + +#ifdef CONFIG_64BIT +# define COND(x) "*" __stringify(x) +#else +# define COND(x) __stringify(x) +#endif #endif /* __ASSEMBLY__ */ #endif diff --git a/arch/parisc/include/uapi/asm/cachectl.h b/arch/parisc/include/uapi/asm/cachectl.h new file mode 100644 index 000000000000..68d6b455498b --- /dev/null +++ b/arch/parisc/include/uapi/asm/cachectl.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ +#ifndef _ASM_CACHECTL +#define _ASM_CACHECTL + +/* + * Options for cacheflush system call + */ +#define ICACHE (1<<0) /* flush instruction cache */ +#define DCACHE (1<<1) /* writeback and flush data cache */ +#define BCACHE (ICACHE|DCACHE) /* flush both caches */ + +#endif /* _ASM_CACHECTL */ diff --git a/arch/parisc/kernel/cache.c b/arch/parisc/kernel/cache.c index ca4a302d4365..b2c6da38a61c 100644 --- a/arch/parisc/kernel/cache.c +++ b/arch/parisc/kernel/cache.c @@ -19,6 +19,7 @@ #include <linux/pagemap.h> #include <linux/sched.h> #include <linux/sched/mm.h> +#include <linux/syscalls.h> #include <asm/pdc.h> #include <asm/cache.h> #include <asm/cacheflush.h> @@ -28,6 +29,7 @@ #include <asm/sections.h> #include <asm/shmparam.h> #include <asm/mmu_context.h> +#include <asm/cachectl.h> int split_tlb __ro_after_init; int dcache_stride __ro_after_init; @@ -774,3 +776,47 @@ void invalidate_kernel_vmap_range(void *vaddr, int size) flush_tlb_kernel_range(start, end); } EXPORT_SYMBOL(invalidate_kernel_vmap_range); + +SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes, + unsigned int, cache) +{ + unsigned long start, end; + ASM_EXCEPTIONTABLE_VAR(error); + + if (bytes == 0) + return 0; + if (cache & ~BCACHE) + return -EINVAL; + if (!access_ok((void __user *) addr, bytes)) + return -EFAULT; + if ((cache_info.dc_size == 0) && (cache_info.ic_size == 0)) + return 0; + + end = addr + bytes; + if (end < addr) + return -EINVAL; /* wrap-around */ + + if (cache & ICACHE) { + start = addr; + __asm__ __volatile__ ( + "1: cmpb," COND(<<) ",n %0,%2,1b\n" + " fic,m %3(%4,%0)\n" + "2:\n" + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b) + : "+r" (start), "+r" (error) + : "r" (end), "r" (icache_stride), "i" (SR_USER)); + } + + if (cache & DCACHE && error == 0) { + start = addr; + __asm__ __volatile__ ( + "1: cmpb," COND(<<) ",n %0,%2,1b\n" + " fdc,m %3(%4,%0)\n" + "2:\n" + ASM_EXCEPTIONTABLE_ENTRY_EFAULT(1b, 2b) + : "+r" (start), "+r" (error) + : "r" (end), "r" (dcache_stride), "i" (SR_USER)); + } + + return error; +} diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl index 0e42fceb2d5e..293c0484447b 100644 --- a/arch/parisc/kernel/syscalls/syscall.tbl +++ b/arch/parisc/kernel/syscalls/syscall.tbl @@ -400,6 +400,7 @@ 353 common pkey_free sys_pkey_free 354 common rseq sys_rseq 355 common kexec_file_load sys_kexec_file_load sys_kexec_file_load +356 common cacheflush sys_cacheflush # up to 402 is unassigned and reserved for arch specific syscalls 403 32 clock_gettime64 sys_clock_gettime sys_clock_gettime 404 32 clock_settime64 sys_clock_settime sys_clock_settime -- 2.40.1