diff options
author | Andrew Waterman <andrew@sifive.com> | 2017-10-25 17:32:16 -0400 |
---|---|---|
committer | Palmer Dabbelt <palmer@sifive.com> | 2017-11-30 15:58:29 -0500 |
commit | 921ebd8f2c081b3cf6c3b29ef4103eef3ff26054 (patch) | |
tree | e3302d6371f434b91b4194da53342095c68363dd | |
parent | 08f051eda33b51e8ee0f45f05bcfe49d0f0caf6b (diff) |
RISC-V: Allow userspace to flush the instruction cache
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.
This patch adds both a system call and a VDSO entry. If possible, we'd
like to avoid having the system call be considered part of the
user-facing ABI and instead restrict that to the VDSO entry -- both just
in general to avoid having additional user-visible ABI to maintain, and
because we'd prefer that users just call the VDSO entry because there
might be a better way to do this in the future (ie, one that doesn't
require entering the kernel).
Signed-off-by: Andrew Waterman <andrew@sifive.com>
Signed-off-by: Palmer Dabbelt <palmer@sifive.com>
-rw-r--r-- | arch/riscv/include/asm/cacheflush.h | 6 | ||||
-rw-r--r-- | arch/riscv/include/asm/vdso-syscalls.h | 28 | ||||
-rw-r--r-- | arch/riscv/include/asm/vdso.h | 4 | ||||
-rw-r--r-- | arch/riscv/kernel/sys_riscv.c | 32 | ||||
-rw-r--r-- | arch/riscv/kernel/syscall_table.c | 2 | ||||
-rw-r--r-- | arch/riscv/kernel/vdso/Makefile | 1 | ||||
-rw-r--r-- | arch/riscv/kernel/vdso/flush_icache.S | 31 | ||||
-rw-r--r-- | arch/riscv/kernel/vdso/vdso.lds.S | 1 |
8 files changed, 105 insertions, 0 deletions
diff --git a/arch/riscv/include/asm/cacheflush.h b/arch/riscv/include/asm/cacheflush.h index 5c9ed39ee2a2..efd89a88d2d0 100644 --- a/arch/riscv/include/asm/cacheflush.h +++ b/arch/riscv/include/asm/cacheflush.h | |||
@@ -52,4 +52,10 @@ void flush_icache_mm(struct mm_struct *mm, bool local); | |||
52 | 52 | ||
53 | #endif /* CONFIG_SMP */ | 53 | #endif /* CONFIG_SMP */ |
54 | 54 | ||
55 | /* | ||
56 | * Bits in sys_riscv_flush_icache()'s flags argument. | ||
57 | */ | ||
58 | #define SYS_RISCV_FLUSH_ICACHE_LOCAL 1UL | ||
59 | #define SYS_RISCV_FLUSH_ICACHE_ALL (SYS_RISCV_FLUSH_ICACHE_LOCAL) | ||
60 | |||
55 | #endif /* _ASM_RISCV_CACHEFLUSH_H */ | 61 | #endif /* _ASM_RISCV_CACHEFLUSH_H */ |
diff --git a/arch/riscv/include/asm/vdso-syscalls.h b/arch/riscv/include/asm/vdso-syscalls.h new file mode 100644 index 000000000000..a2ccf1894929 --- /dev/null +++ b/arch/riscv/include/asm/vdso-syscalls.h | |||
@@ -0,0 +1,28 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 SiFive | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | * | ||
13 | * You should have received a copy of the GNU General Public License | ||
14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
15 | */ | ||
16 | |||
17 | #ifndef _ASM_RISCV_VDSO_SYSCALLS_H | ||
18 | #define _ASM_RISCV_VDSO_SYSCALLS_H | ||
19 | |||
20 | #ifdef CONFIG_SMP | ||
21 | |||
22 | /* These syscalls are only used by the vDSO and are not in the uapi. */ | ||
23 | #define __NR_riscv_flush_icache (__NR_arch_specific_syscall + 15) | ||
24 | __SYSCALL(__NR_riscv_flush_icache, sys_riscv_flush_icache) | ||
25 | |||
26 | #endif | ||
27 | |||
28 | #endif /* _ASM_RISCV_VDSO_H */ | ||
diff --git a/arch/riscv/include/asm/vdso.h b/arch/riscv/include/asm/vdso.h index 602f61257553..541544d64c33 100644 --- a/arch/riscv/include/asm/vdso.h +++ b/arch/riscv/include/asm/vdso.h | |||
@@ -38,4 +38,8 @@ struct vdso_data { | |||
38 | (void __user *)((unsigned long)(base) + __vdso_##name); \ | 38 | (void __user *)((unsigned long)(base) + __vdso_##name); \ |
39 | }) | 39 | }) |
40 | 40 | ||
41 | #ifdef CONFIG_SMP | ||
42 | asmlinkage long sys_riscv_flush_icache(uintptr_t, uintptr_t, uintptr_t); | ||
43 | #endif | ||
44 | |||
41 | #endif /* _ASM_RISCV_VDSO_H */ | 45 | #endif /* _ASM_RISCV_VDSO_H */ |
diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index 4351be7d0533..c6c037eabaf6 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/syscalls.h> | 16 | #include <linux/syscalls.h> |
17 | #include <asm/cmpxchg.h> | 17 | #include <asm/cmpxchg.h> |
18 | #include <asm/unistd.h> | 18 | #include <asm/unistd.h> |
19 | #include <asm/cacheflush.h> | ||
19 | 20 | ||
20 | static long riscv_sys_mmap(unsigned long addr, unsigned long len, | 21 | static long riscv_sys_mmap(unsigned long addr, unsigned long len, |
21 | unsigned long prot, unsigned long flags, | 22 | unsigned long prot, unsigned long flags, |
@@ -47,3 +48,34 @@ SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, | |||
47 | return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12); | 48 | return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12); |
48 | } | 49 | } |
49 | #endif /* !CONFIG_64BIT */ | 50 | #endif /* !CONFIG_64BIT */ |
51 | |||
52 | #ifdef CONFIG_SMP | ||
53 | /* | ||
54 | * Allows the instruction cache to be flushed from userspace. Despite RISC-V | ||
55 | * having a direct 'fence.i' instruction available to userspace (which we | ||
56 | * can't trap!), that's not actually viable when running on Linux because the | ||
57 | * kernel might schedule a process on another hart. There is no way for | ||
58 | * userspace to handle this without invoking the kernel (as it doesn't know the | ||
59 | * thread->hart mappings), so we've defined a RISC-V specific system call to | ||
60 | * flush the instruction cache. | ||
61 | * | ||
62 | * sys_riscv_flush_icache() is defined to flush the instruction cache over an | ||
63 | * address range, with the flush applying to either all threads or just the | ||
64 | * caller. We don't currently do anything with the address range, that's just | ||
65 | * in there for forwards compatibility. | ||
66 | */ | ||
67 | SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, uintptr_t, end, | ||
68 | uintptr_t, flags) | ||
69 | { | ||
70 | struct mm_struct *mm = current->mm; | ||
71 | bool local = (flags & SYS_RISCV_FLUSH_ICACHE_LOCAL) != 0; | ||
72 | |||
73 | /* Check the reserved flags. */ | ||
74 | if (unlikely(flags & !SYS_RISCV_FLUSH_ICACHE_ALL)) | ||
75 | return -EINVAL; | ||
76 | |||
77 | flush_icache_mm(mm, local); | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | #endif | ||
diff --git a/arch/riscv/kernel/syscall_table.c b/arch/riscv/kernel/syscall_table.c index 4e30dc5fb593..a5bd6401f95e 100644 --- a/arch/riscv/kernel/syscall_table.c +++ b/arch/riscv/kernel/syscall_table.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/linkage.h> | 15 | #include <linux/linkage.h> |
16 | #include <linux/syscalls.h> | 16 | #include <linux/syscalls.h> |
17 | #include <asm-generic/syscalls.h> | 17 | #include <asm-generic/syscalls.h> |
18 | #include <asm/vdso.h> | ||
18 | 19 | ||
19 | #undef __SYSCALL | 20 | #undef __SYSCALL |
20 | #define __SYSCALL(nr, call) [nr] = (call), | 21 | #define __SYSCALL(nr, call) [nr] = (call), |
@@ -22,4 +23,5 @@ | |||
22 | void *sys_call_table[__NR_syscalls] = { | 23 | void *sys_call_table[__NR_syscalls] = { |
23 | [0 ... __NR_syscalls - 1] = sys_ni_syscall, | 24 | [0 ... __NR_syscalls - 1] = sys_ni_syscall, |
24 | #include <asm/unistd.h> | 25 | #include <asm/unistd.h> |
26 | #include <asm/vdso-syscalls.h> | ||
25 | }; | 27 | }; |
diff --git a/arch/riscv/kernel/vdso/Makefile b/arch/riscv/kernel/vdso/Makefile index 2dcc4f3070bc..324568d33921 100644 --- a/arch/riscv/kernel/vdso/Makefile +++ b/arch/riscv/kernel/vdso/Makefile | |||
@@ -6,6 +6,7 @@ vdso-syms += gettimeofday | |||
6 | vdso-syms += clock_gettime | 6 | vdso-syms += clock_gettime |
7 | vdso-syms += clock_getres | 7 | vdso-syms += clock_getres |
8 | vdso-syms += getcpu | 8 | vdso-syms += getcpu |
9 | vdso-syms += flush_icache | ||
9 | 10 | ||
10 | # Files to link into the vdso | 11 | # Files to link into the vdso |
11 | obj-vdso = $(patsubst %, %.o, $(vdso-syms)) | 12 | obj-vdso = $(patsubst %, %.o, $(vdso-syms)) |
diff --git a/arch/riscv/kernel/vdso/flush_icache.S b/arch/riscv/kernel/vdso/flush_icache.S new file mode 100644 index 000000000000..b0fbad74e873 --- /dev/null +++ b/arch/riscv/kernel/vdso/flush_icache.S | |||
@@ -0,0 +1,31 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2017 SiFive | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU General Public License | ||
6 | * as published by the Free Software Foundation, version 2. | ||
7 | * | ||
8 | * This program is distributed in the hope that it will be useful, | ||
9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
11 | * GNU General Public License for more details. | ||
12 | */ | ||
13 | |||
14 | #include <linux/linkage.h> | ||
15 | #include <asm/unistd.h> | ||
16 | #include <asm/vdso-syscalls.h> | ||
17 | |||
18 | .text | ||
19 | /* int __vdso_flush_icache(void *start, void *end, unsigned long flags); */ | ||
20 | ENTRY(__vdso_flush_icache) | ||
21 | .cfi_startproc | ||
22 | #ifdef CONFIG_SMP | ||
23 | li a7, __NR_riscv_flush_icache | ||
24 | ecall | ||
25 | #else | ||
26 | fence.i | ||
27 | li a0, 0 | ||
28 | #endif | ||
29 | ret | ||
30 | .cfi_endproc | ||
31 | ENDPROC(__vdso_flush_icache) | ||
diff --git a/arch/riscv/kernel/vdso/vdso.lds.S b/arch/riscv/kernel/vdso/vdso.lds.S index c7543c6a00f9..cd1d47e0724b 100644 --- a/arch/riscv/kernel/vdso/vdso.lds.S +++ b/arch/riscv/kernel/vdso/vdso.lds.S | |||
@@ -74,6 +74,7 @@ VERSION | |||
74 | __vdso_clock_gettime; | 74 | __vdso_clock_gettime; |
75 | __vdso_clock_getres; | 75 | __vdso_clock_getres; |
76 | __vdso_getcpu; | 76 | __vdso_getcpu; |
77 | __vdso_flush_icache; | ||
77 | local: *; | 78 | local: *; |
78 | }; | 79 | }; |
79 | } | 80 | } |