diff options
Diffstat (limited to 'arch/riscv/kernel/sys_riscv.c')
| -rw-r--r-- | arch/riscv/kernel/sys_riscv.c | 33 | 
1 files changed, 32 insertions, 1 deletions
| diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index 4351be7d0533..a2ae936a093e 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c @@ -14,8 +14,8 @@   */  #include <linux/syscalls.h> -#include <asm/cmpxchg.h>  #include <asm/unistd.h> +#include <asm/cacheflush.h>  static long riscv_sys_mmap(unsigned long addr, unsigned long len,  			   unsigned long prot, unsigned long flags, @@ -47,3 +47,34 @@ SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len,  	return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12);  }  #endif /* !CONFIG_64BIT */ + +#ifdef CONFIG_SMP +/* + * Allows the instruction cache to be flushed from userspace.  Despite RISC-V + * having a direct 'fence.i' instruction available to userspace (which we + * can't trap!), that's not actually viable when running on Linux because the + * kernel might schedule a process on another hart.  There is no way for + * userspace to handle this without invoking the kernel (as it doesn't know the + * thread->hart mappings), so we've defined a RISC-V specific system call to + * flush the instruction cache. + * + * sys_riscv_flush_icache() is defined to flush the instruction cache over an + * address range, with the flush applying to either all threads or just the + * caller.  We don't currently do anything with the address range, that's just + * in there for forwards compatibility. + */ +SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, uintptr_t, end, +	uintptr_t, flags) +{ +	struct mm_struct *mm = current->mm; +	bool local = (flags & SYS_RISCV_FLUSH_ICACHE_LOCAL) != 0; + +	/* Check the reserved flags. */ +	if (unlikely(flags & !SYS_RISCV_FLUSH_ICACHE_ALL)) +		return -EINVAL; + +	flush_icache_mm(mm, local); + +	return 0; +} +#endif |