Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Andrew Waterman and committed by
Palmer Dabbelt
921ebd8f 08f051ed

+105
+6
arch/riscv/include/asm/cacheflush.h
··· 52 52 53 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 61 #endif /* _ASM_RISCV_CACHEFLUSH_H */
+28
arch/riscv/include/asm/vdso-syscalls.h
··· 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 */
+4
arch/riscv/include/asm/vdso.h
··· 38 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 45 #endif /* _ASM_RISCV_VDSO_H */
+32
arch/riscv/kernel/sys_riscv.c
··· 16 16 #include <linux/syscalls.h> 17 17 #include <asm/cmpxchg.h> 18 18 #include <asm/unistd.h> 19 + #include <asm/cacheflush.h> 19 20 20 21 static long riscv_sys_mmap(unsigned long addr, unsigned long len, 21 22 unsigned long prot, unsigned long flags, ··· 48 47 return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12); 49 48 } 50 49 #endif /* !CONFIG_64BIT */ 50 + 51 + #ifdef CONFIG_SMP 52 + /* 53 + * Allows the instruction cache to be flushed from userspace. Despite RISC-V 54 + * having a direct 'fence.i' instruction available to userspace (which we 55 + * can't trap!), that's not actually viable when running on Linux because the 56 + * kernel might schedule a process on another hart. There is no way for 57 + * userspace to handle this without invoking the kernel (as it doesn't know the 58 + * thread->hart mappings), so we've defined a RISC-V specific system call to 59 + * flush the instruction cache. 60 + * 61 + * sys_riscv_flush_icache() is defined to flush the instruction cache over an 62 + * address range, with the flush applying to either all threads or just the 63 + * caller. We don't currently do anything with the address range, that's just 64 + * in there for forwards compatibility. 65 + */ 66 + SYSCALL_DEFINE3(riscv_flush_icache, uintptr_t, start, uintptr_t, end, 67 + uintptr_t, flags) 68 + { 69 + struct mm_struct *mm = current->mm; 70 + bool local = (flags & SYS_RISCV_FLUSH_ICACHE_LOCAL) != 0; 71 + 72 + /* Check the reserved flags. */ 73 + if (unlikely(flags & !SYS_RISCV_FLUSH_ICACHE_ALL)) 74 + return -EINVAL; 75 + 76 + flush_icache_mm(mm, local); 77 + 78 + return 0; 79 + } 80 + #endif
+2
arch/riscv/kernel/syscall_table.c
··· 15 15 #include <linux/linkage.h> 16 16 #include <linux/syscalls.h> 17 17 #include <asm-generic/syscalls.h> 18 + #include <asm/vdso.h> 18 19 19 20 #undef __SYSCALL 20 21 #define __SYSCALL(nr, call) [nr] = (call), ··· 23 22 void *sys_call_table[__NR_syscalls] = { 24 23 [0 ... __NR_syscalls - 1] = sys_ni_syscall, 25 24 #include <asm/unistd.h> 25 + #include <asm/vdso-syscalls.h> 26 26 };
+1
arch/riscv/kernel/vdso/Makefile
··· 6 6 vdso-syms += clock_gettime 7 7 vdso-syms += clock_getres 8 8 vdso-syms += getcpu 9 + vdso-syms += flush_icache 9 10 10 11 # Files to link into the vdso 11 12 obj-vdso = $(patsubst %, %.o, $(vdso-syms))
+31
arch/riscv/kernel/vdso/flush_icache.S
··· 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)
+1
arch/riscv/kernel/vdso/vdso.lds.S
··· 74 74 __vdso_clock_gettime; 75 75 __vdso_clock_getres; 76 76 __vdso_getcpu; 77 + __vdso_flush_icache; 77 78 local: *; 78 79 }; 79 80 }