1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) 2012 Regents of the University of California |
4 | * Copyright (C) 2014 Darius Rad <darius@bluespec.com> |
5 | * Copyright (C) 2017 SiFive |
6 | */ |
7 | |
8 | #include <linux/syscalls.h> |
9 | #include <asm/cacheflush.h> |
10 | #include <asm-generic/mman-common.h> |
11 | |
12 | static long riscv_sys_mmap(unsigned long addr, unsigned long len, |
13 | unsigned long prot, unsigned long flags, |
14 | unsigned long fd, off_t offset, |
15 | unsigned long page_shift_offset) |
16 | { |
17 | if (unlikely(offset & (~PAGE_MASK >> page_shift_offset))) |
18 | return -EINVAL; |
19 | |
20 | return ksys_mmap_pgoff(addr, len, prot, flags, fd, |
21 | pgoff: offset >> (PAGE_SHIFT - page_shift_offset)); |
22 | } |
23 | |
24 | #ifdef CONFIG_64BIT |
25 | SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len, |
26 | unsigned long, prot, unsigned long, flags, |
27 | unsigned long, fd, off_t, offset) |
28 | { |
29 | return riscv_sys_mmap(addr, len, prot, flags, fd, offset, page_shift_offset: 0); |
30 | } |
31 | #endif |
32 | |
33 | #if defined(CONFIG_32BIT) || defined(CONFIG_COMPAT) |
34 | SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, |
35 | unsigned long, prot, unsigned long, flags, |
36 | unsigned long, fd, off_t, offset) |
37 | { |
38 | /* |
39 | * Note that the shift for mmap2 is constant (12), |
40 | * regardless of PAGE_SIZE |
41 | */ |
42 | return riscv_sys_mmap(addr, len, prot, flags, fd, offset, page_shift_offset: 12); |
43 | } |
44 | #endif |
45 | |
46 | /* |
47 | * Allows the instruction cache to be flushed from userspace. Despite RISC-V |
48 | * having a direct 'fence.i' instruction available to userspace (which we |
49 | * can't trap!), that's not actually viable when running on Linux because the |
50 | * kernel might schedule a process on another hart. There is no way for |
51 | * userspace to handle this without invoking the kernel (as it doesn't know the |
52 | * thread->hart mappings), so we've defined a RISC-V specific system call to |
53 | * flush the instruction cache. |
54 | * |
55 | * sys_riscv_flush_icache() is defined to flush the instruction cache over an |
56 | * address range, with the flush applying to either all threads or just the |
57 | * caller. We don't currently do anything with the address range, that's just |
58 | * in there for forwards compatibility. |
59 | */ |
60 | SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, uintptr_t, end, |
61 | uintptr_t, flags) |
62 | { |
63 | /* Check the reserved flags. */ |
64 | if (unlikely(flags & ~SYS_RISCV_FLUSH_ICACHE_ALL)) |
65 | return -EINVAL; |
66 | |
67 | flush_icache_mm(current->mm, flags & SYS_RISCV_FLUSH_ICACHE_LOCAL); |
68 | |
69 | return 0; |
70 | } |
71 | |
72 | /* Not defined using SYSCALL_DEFINE0 to avoid error injection */ |
73 | asmlinkage long __riscv_sys_ni_syscall(const struct pt_regs *__unused) |
74 | { |
75 | return -ENOSYS; |
76 | } |
77 | |