diff options
Diffstat (limited to 'arch/riscv/kernel/sys_riscv.c')
-rw-r--r-- | arch/riscv/kernel/sys_riscv.c | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c new file mode 100644 index 000000000..5d3f2fbeb --- /dev/null +++ b/arch/riscv/kernel/sys_riscv.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (C) 2012 Regents of the University of California + * Copyright (C) 2014 Darius Rad <darius@bluespec.com> + * Copyright (C) 2017 SiFive + */ + +#include <linux/syscalls.h> +#include <asm/unistd.h> +#include <asm/cacheflush.h> +#include <asm-generic/mman-common.h> + +static long riscv_sys_mmap(unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, + unsigned long fd, off_t offset, + unsigned long page_shift_offset) +{ + if (unlikely(offset & (~PAGE_MASK >> page_shift_offset))) + return -EINVAL; + + return ksys_mmap_pgoff(addr, len, prot, flags, fd, + offset >> (PAGE_SHIFT - page_shift_offset)); +} + +#ifdef CONFIG_64BIT +SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, + unsigned long, fd, off_t, offset) +{ + return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 0); +} +#endif + +#if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) +SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, + unsigned long, prot, unsigned long, flags, + unsigned long, fd, off_t, offset) +{ + /* + * Note that the shift for mmap2 is constant (12), + * regardless of PAGE_SIZE + */ + return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12); +} +#endif + +/* + * 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) +{ + /* Check the reserved flags. */ + if (unlikely(flags & ~SYS_RISCV_FLUSH_ICACHE_ALL)) + return -EINVAL; + + flush_icache_mm(current->mm, flags & SYS_RISCV_FLUSH_ICACHE_LOCAL); + + return 0; +} |