diff options
Diffstat (limited to 'arch/riscv/kernel')
-rw-r--r-- | arch/riscv/kernel/head.S | 3 | ||||
-rw-r--r-- | arch/riscv/kernel/riscv_ksyms.c | 3 | ||||
-rw-r--r-- | arch/riscv/kernel/setup.c | 5 | ||||
-rw-r--r-- | arch/riscv/kernel/smp.c | 55 | ||||
-rw-r--r-- | arch/riscv/kernel/sys_riscv.c | 33 | ||||
-rw-r--r-- | arch/riscv/kernel/syscall_table.c | 2 | ||||
-rw-r--r-- | arch/riscv/kernel/vdso/Makefile | 7 | ||||
-rw-r--r-- | arch/riscv/kernel/vdso/clock_getres.S | 26 | ||||
-rw-r--r-- | arch/riscv/kernel/vdso/clock_gettime.S | 26 | ||||
-rw-r--r-- | arch/riscv/kernel/vdso/flush_icache.S | 31 | ||||
-rw-r--r-- | arch/riscv/kernel/vdso/getcpu.S | 26 | ||||
-rw-r--r-- | arch/riscv/kernel/vdso/gettimeofday.S | 26 | ||||
-rw-r--r-- | arch/riscv/kernel/vdso/vdso.lds.S | 7 |
13 files changed, 243 insertions, 7 deletions
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S index 76af908f87c1..78f670d70133 100644 --- a/arch/riscv/kernel/head.S +++ b/arch/riscv/kernel/head.S | |||
@@ -152,6 +152,3 @@ END(_start) | |||
152 | __PAGE_ALIGNED_BSS | 152 | __PAGE_ALIGNED_BSS |
153 | /* Empty zero page */ | 153 | /* Empty zero page */ |
154 | .balign PAGE_SIZE | 154 | .balign PAGE_SIZE |
155 | ENTRY(empty_zero_page) | ||
156 | .fill (empty_zero_page + PAGE_SIZE) - ., 1, 0x00 | ||
157 | END(empty_zero_page) | ||
diff --git a/arch/riscv/kernel/riscv_ksyms.c b/arch/riscv/kernel/riscv_ksyms.c index 23cc81ec9e94..551734248748 100644 --- a/arch/riscv/kernel/riscv_ksyms.c +++ b/arch/riscv/kernel/riscv_ksyms.c | |||
@@ -12,4 +12,7 @@ | |||
12 | /* | 12 | /* |
13 | * Assembly functions that may be used (directly or indirectly) by modules | 13 | * Assembly functions that may be used (directly or indirectly) by modules |
14 | */ | 14 | */ |
15 | EXPORT_SYMBOL(__clear_user); | ||
15 | EXPORT_SYMBOL(__copy_user); | 16 | EXPORT_SYMBOL(__copy_user); |
17 | EXPORT_SYMBOL(memset); | ||
18 | EXPORT_SYMBOL(memcpy); | ||
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c index de7db114c315..8fbb6749910d 100644 --- a/arch/riscv/kernel/setup.c +++ b/arch/riscv/kernel/setup.c | |||
@@ -58,7 +58,12 @@ static char __initdata builtin_cmdline[COMMAND_LINE_SIZE] = CONFIG_CMDLINE; | |||
58 | #endif /* CONFIG_CMDLINE_BOOL */ | 58 | #endif /* CONFIG_CMDLINE_BOOL */ |
59 | 59 | ||
60 | unsigned long va_pa_offset; | 60 | unsigned long va_pa_offset; |
61 | EXPORT_SYMBOL(va_pa_offset); | ||
61 | unsigned long pfn_base; | 62 | unsigned long pfn_base; |
63 | EXPORT_SYMBOL(pfn_base); | ||
64 | |||
65 | unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)] __page_aligned_bss; | ||
66 | EXPORT_SYMBOL(empty_zero_page); | ||
62 | 67 | ||
63 | /* The lucky hart to first increment this variable will boot the other cores */ | 68 | /* The lucky hart to first increment this variable will boot the other cores */ |
64 | atomic_t hart_lottery; | 69 | atomic_t hart_lottery; |
diff --git a/arch/riscv/kernel/smp.c b/arch/riscv/kernel/smp.c index b4a71ec5906f..6d3962435720 100644 --- a/arch/riscv/kernel/smp.c +++ b/arch/riscv/kernel/smp.c | |||
@@ -38,6 +38,13 @@ enum ipi_message_type { | |||
38 | IPI_MAX | 38 | IPI_MAX |
39 | }; | 39 | }; |
40 | 40 | ||
41 | |||
42 | /* Unsupported */ | ||
43 | int setup_profiling_timer(unsigned int multiplier) | ||
44 | { | ||
45 | return -EINVAL; | ||
46 | } | ||
47 | |||
41 | irqreturn_t handle_ipi(void) | 48 | irqreturn_t handle_ipi(void) |
42 | { | 49 | { |
43 | unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; | 50 | unsigned long *pending_ipis = &ipi_data[smp_processor_id()].bits; |
@@ -108,3 +115,51 @@ void smp_send_reschedule(int cpu) | |||
108 | { | 115 | { |
109 | send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); | 116 | send_ipi_message(cpumask_of(cpu), IPI_RESCHEDULE); |
110 | } | 117 | } |
118 | |||
119 | /* | ||
120 | * Performs an icache flush for the given MM context. RISC-V has no direct | ||
121 | * mechanism for instruction cache shoot downs, so instead we send an IPI that | ||
122 | * informs the remote harts they need to flush their local instruction caches. | ||
123 | * To avoid pathologically slow behavior in a common case (a bunch of | ||
124 | * single-hart processes on a many-hart machine, ie 'make -j') we avoid the | ||
125 | * IPIs for harts that are not currently executing a MM context and instead | ||
126 | * schedule a deferred local instruction cache flush to be performed before | ||
127 | * execution resumes on each hart. | ||
128 | */ | ||
129 | void flush_icache_mm(struct mm_struct *mm, bool local) | ||
130 | { | ||
131 | unsigned int cpu; | ||
132 | cpumask_t others, *mask; | ||
133 | |||
134 | preempt_disable(); | ||
135 | |||
136 | /* Mark every hart's icache as needing a flush for this MM. */ | ||
137 | mask = &mm->context.icache_stale_mask; | ||
138 | cpumask_setall(mask); | ||
139 | /* Flush this hart's I$ now, and mark it as flushed. */ | ||
140 | cpu = smp_processor_id(); | ||
141 | cpumask_clear_cpu(cpu, mask); | ||
142 | local_flush_icache_all(); | ||
143 | |||
144 | /* | ||
145 | * Flush the I$ of other harts concurrently executing, and mark them as | ||
146 | * flushed. | ||
147 | */ | ||
148 | cpumask_andnot(&others, mm_cpumask(mm), cpumask_of(cpu)); | ||
149 | local |= cpumask_empty(&others); | ||
150 | if (mm != current->active_mm || !local) | ||
151 | sbi_remote_fence_i(others.bits); | ||
152 | else { | ||
153 | /* | ||
154 | * It's assumed that at least one strongly ordered operation is | ||
155 | * performed on this hart between setting a hart's cpumask bit | ||
156 | * and scheduling this MM context on that hart. Sending an SBI | ||
157 | * remote message will do this, but in the case where no | ||
158 | * messages are sent we still need to order this hart's writes | ||
159 | * with flush_icache_deferred(). | ||
160 | */ | ||
161 | smp_mb(); | ||
162 | } | ||
163 | |||
164 | preempt_enable(); | ||
165 | } | ||
diff --git a/arch/riscv/kernel/sys_riscv.c b/arch/riscv/kernel/sys_riscv.c index 4351be7d0533..a2ae936a093e 100644 --- a/arch/riscv/kernel/sys_riscv.c +++ b/arch/riscv/kernel/sys_riscv.c | |||
@@ -14,8 +14,8 @@ | |||
14 | */ | 14 | */ |
15 | 15 | ||
16 | #include <linux/syscalls.h> | 16 | #include <linux/syscalls.h> |
17 | #include <asm/cmpxchg.h> | ||
18 | #include <asm/unistd.h> | 17 | #include <asm/unistd.h> |
18 | #include <asm/cacheflush.h> | ||
19 | 19 | ||
20 | static long riscv_sys_mmap(unsigned long addr, unsigned long len, | 20 | static long riscv_sys_mmap(unsigned long addr, unsigned long len, |
21 | unsigned long prot, unsigned long flags, | 21 | unsigned long prot, unsigned long flags, |
@@ -47,3 +47,34 @@ SYSCALL_DEFINE6(mmap2, unsigned long, addr, unsigned long, len, | |||
47 | return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12); | 47 | return riscv_sys_mmap(addr, len, prot, flags, fd, offset, 12); |
48 | } | 48 | } |
49 | #endif /* !CONFIG_64BIT */ | 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 | ||
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 523d0a8ac8db..324568d33921 100644 --- a/arch/riscv/kernel/vdso/Makefile +++ b/arch/riscv/kernel/vdso/Makefile | |||
@@ -1,7 +1,12 @@ | |||
1 | # Copied from arch/tile/kernel/vdso/Makefile | 1 | # Copied from arch/tile/kernel/vdso/Makefile |
2 | 2 | ||
3 | # Symbols present in the vdso | 3 | # Symbols present in the vdso |
4 | vdso-syms = rt_sigreturn | 4 | vdso-syms = rt_sigreturn |
5 | vdso-syms += gettimeofday | ||
6 | vdso-syms += clock_gettime | ||
7 | vdso-syms += clock_getres | ||
8 | vdso-syms += getcpu | ||
9 | vdso-syms += flush_icache | ||
5 | 10 | ||
6 | # Files to link into the vdso | 11 | # Files to link into the vdso |
7 | obj-vdso = $(patsubst %, %.o, $(vdso-syms)) | 12 | obj-vdso = $(patsubst %, %.o, $(vdso-syms)) |
diff --git a/arch/riscv/kernel/vdso/clock_getres.S b/arch/riscv/kernel/vdso/clock_getres.S new file mode 100644 index 000000000000..edf7e2339648 --- /dev/null +++ b/arch/riscv/kernel/vdso/clock_getres.S | |||
@@ -0,0 +1,26 @@ | |||
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 | |||
17 | .text | ||
18 | /* int __vdso_clock_getres(clockid_t clock_id, struct timespec *res); */ | ||
19 | ENTRY(__vdso_clock_getres) | ||
20 | .cfi_startproc | ||
21 | /* For now, just do the syscall. */ | ||
22 | li a7, __NR_clock_getres | ||
23 | ecall | ||
24 | ret | ||
25 | .cfi_endproc | ||
26 | ENDPROC(__vdso_clock_getres) | ||
diff --git a/arch/riscv/kernel/vdso/clock_gettime.S b/arch/riscv/kernel/vdso/clock_gettime.S new file mode 100644 index 000000000000..aac65676c6d5 --- /dev/null +++ b/arch/riscv/kernel/vdso/clock_gettime.S | |||
@@ -0,0 +1,26 @@ | |||
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 | |||
17 | .text | ||
18 | /* int __vdso_clock_gettime(clockid_t clock_id, struct timespec *tp); */ | ||
19 | ENTRY(__vdso_clock_gettime) | ||
20 | .cfi_startproc | ||
21 | /* For now, just do the syscall. */ | ||
22 | li a7, __NR_clock_gettime | ||
23 | ecall | ||
24 | ret | ||
25 | .cfi_endproc | ||
26 | ENDPROC(__vdso_clock_gettime) | ||
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/getcpu.S b/arch/riscv/kernel/vdso/getcpu.S new file mode 100644 index 000000000000..cc7e98924484 --- /dev/null +++ b/arch/riscv/kernel/vdso/getcpu.S | |||
@@ -0,0 +1,26 @@ | |||
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 | |||
17 | .text | ||
18 | /* int __vdso_getcpu(unsigned *cpu, unsigned *node, void *unused); */ | ||
19 | ENTRY(__vdso_getcpu) | ||
20 | .cfi_startproc | ||
21 | /* For now, just do the syscall. */ | ||
22 | li a7, __NR_getcpu | ||
23 | ecall | ||
24 | ret | ||
25 | .cfi_endproc | ||
26 | ENDPROC(__vdso_getcpu) | ||
diff --git a/arch/riscv/kernel/vdso/gettimeofday.S b/arch/riscv/kernel/vdso/gettimeofday.S new file mode 100644 index 000000000000..da85d33e8990 --- /dev/null +++ b/arch/riscv/kernel/vdso/gettimeofday.S | |||
@@ -0,0 +1,26 @@ | |||
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 | |||
17 | .text | ||
18 | /* int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz); */ | ||
19 | ENTRY(__vdso_gettimeofday) | ||
20 | .cfi_startproc | ||
21 | /* For now, just do the syscall. */ | ||
22 | li a7, __NR_gettimeofday | ||
23 | ecall | ||
24 | ret | ||
25 | .cfi_endproc | ||
26 | ENDPROC(__vdso_gettimeofday) | ||
diff --git a/arch/riscv/kernel/vdso/vdso.lds.S b/arch/riscv/kernel/vdso/vdso.lds.S index 8c9dce95c11d..cd1d47e0724b 100644 --- a/arch/riscv/kernel/vdso/vdso.lds.S +++ b/arch/riscv/kernel/vdso/vdso.lds.S | |||
@@ -70,8 +70,11 @@ VERSION | |||
70 | LINUX_4.15 { | 70 | LINUX_4.15 { |
71 | global: | 71 | global: |
72 | __vdso_rt_sigreturn; | 72 | __vdso_rt_sigreturn; |
73 | __vdso_cmpxchg32; | 73 | __vdso_gettimeofday; |
74 | __vdso_cmpxchg64; | 74 | __vdso_clock_gettime; |
75 | __vdso_clock_getres; | ||
76 | __vdso_getcpu; | ||
77 | __vdso_flush_icache; | ||
75 | local: *; | 78 | local: *; |
76 | }; | 79 | }; |
77 | } | 80 | } |