aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew Waterman <andrew@sifive.com>2017-10-25 17:32:16 -0400
committerPalmer Dabbelt <palmer@sifive.com>2017-11-30 15:58:29 -0500
commit921ebd8f2c081b3cf6c3b29ef4103eef3ff26054 (patch)
treee3302d6371f434b91b4194da53342095c68363dd
parent08f051eda33b51e8ee0f45f05bcfe49d0f0caf6b (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.h6
-rw-r--r--arch/riscv/include/asm/vdso-syscalls.h28
-rw-r--r--arch/riscv/include/asm/vdso.h4
-rw-r--r--arch/riscv/kernel/sys_riscv.c32
-rw-r--r--arch/riscv/kernel/syscall_table.c2
-rw-r--r--arch/riscv/kernel/vdso/Makefile1
-rw-r--r--arch/riscv/kernel/vdso/flush_icache.S31
-rw-r--r--arch/riscv/kernel/vdso/vdso.lds.S1
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
42asmlinkage 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
20static long riscv_sys_mmap(unsigned long addr, unsigned long len, 21static 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 */
67SYSCALL_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 @@
22void *sys_call_table[__NR_syscalls] = { 23void *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
6vdso-syms += clock_gettime 6vdso-syms += clock_gettime
7vdso-syms += clock_getres 7vdso-syms += clock_getres
8vdso-syms += getcpu 8vdso-syms += getcpu
9vdso-syms += flush_icache
9 10
10# Files to link into the vdso 11# Files to link into the vdso
11obj-vdso = $(patsubst %, %.o, $(vdso-syms)) 12obj-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); */
20ENTRY(__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
31ENDPROC(__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}