diff options
-rw-r--r-- | arch/riscv/Kconfig | 12 | ||||
-rw-r--r-- | arch/riscv/Makefile | 8 | ||||
-rw-r--r-- | arch/riscv/configs/defconfig | 2 | ||||
-rw-r--r-- | arch/riscv/include/asm/atomic.h | 417 | ||||
-rw-r--r-- | arch/riscv/include/asm/barrier.h | 15 | ||||
-rw-r--r-- | arch/riscv/include/asm/cmpxchg.h | 391 | ||||
-rw-r--r-- | arch/riscv/include/asm/fence.h | 12 | ||||
-rw-r--r-- | arch/riscv/include/asm/ftrace.h | 56 | ||||
-rw-r--r-- | arch/riscv/include/asm/module.h | 113 | ||||
-rw-r--r-- | arch/riscv/include/asm/spinlock.h | 29 | ||||
-rw-r--r-- | arch/riscv/include/uapi/asm/elf.h | 7 | ||||
-rw-r--r-- | arch/riscv/kernel/Makefile | 6 | ||||
-rw-r--r-- | arch/riscv/kernel/ftrace.c | 175 | ||||
-rw-r--r-- | arch/riscv/kernel/mcount-dyn.S | 239 | ||||
-rw-r--r-- | arch/riscv/kernel/mcount.S | 22 | ||||
-rw-r--r-- | arch/riscv/kernel/module-sections.c | 156 | ||||
-rw-r--r-- | arch/riscv/kernel/module.c | 179 | ||||
-rw-r--r-- | arch/riscv/kernel/module.lds | 8 | ||||
-rw-r--r-- | arch/riscv/kernel/stacktrace.c | 6 | ||||
-rwxr-xr-x | scripts/recordmcount.pl | 5 |
20 files changed, 1603 insertions, 255 deletions
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig index 148865de1692..23d8acca5c90 100644 --- a/arch/riscv/Kconfig +++ b/arch/riscv/Kconfig | |||
@@ -115,6 +115,9 @@ config ARCH_RV64I | |||
115 | select 64BIT | 115 | select 64BIT |
116 | select HAVE_FUNCTION_TRACER | 116 | select HAVE_FUNCTION_TRACER |
117 | select HAVE_FUNCTION_GRAPH_TRACER | 117 | select HAVE_FUNCTION_GRAPH_TRACER |
118 | select HAVE_FTRACE_MCOUNT_RECORD | ||
119 | select HAVE_DYNAMIC_FTRACE | ||
120 | select HAVE_DYNAMIC_FTRACE_WITH_REGS | ||
118 | 121 | ||
119 | endchoice | 122 | endchoice |
120 | 123 | ||
@@ -132,6 +135,10 @@ choice | |||
132 | bool "medium any code model" | 135 | bool "medium any code model" |
133 | endchoice | 136 | endchoice |
134 | 137 | ||
138 | config MODULE_SECTIONS | ||
139 | bool | ||
140 | select HAVE_MOD_ARCH_SPECIFIC | ||
141 | |||
135 | choice | 142 | choice |
136 | prompt "Maximum Physical Memory" | 143 | prompt "Maximum Physical Memory" |
137 | default MAXPHYSMEM_2GB if 32BIT | 144 | default MAXPHYSMEM_2GB if 32BIT |
@@ -142,6 +149,7 @@ choice | |||
142 | bool "2GiB" | 149 | bool "2GiB" |
143 | config MAXPHYSMEM_128GB | 150 | config MAXPHYSMEM_128GB |
144 | depends on 64BIT && CMODEL_MEDANY | 151 | depends on 64BIT && CMODEL_MEDANY |
152 | select MODULE_SECTIONS if MODULES | ||
145 | bool "128GiB" | 153 | bool "128GiB" |
146 | endchoice | 154 | endchoice |
147 | 155 | ||
@@ -282,7 +290,7 @@ config CMDLINE_BOOL | |||
282 | in CONFIG_CMDLINE. | 290 | in CONFIG_CMDLINE. |
283 | 291 | ||
284 | The built-in options will be concatenated to the default command | 292 | The built-in options will be concatenated to the default command |
285 | line if CMDLINE_OVERRIDE is set to 'N'. Otherwise, the default | 293 | line if CMDLINE_FORCE is set to 'N'. Otherwise, the default |
286 | command line will be ignored and replaced by the built-in string. | 294 | command line will be ignored and replaced by the built-in string. |
287 | 295 | ||
288 | config CMDLINE | 296 | config CMDLINE |
@@ -292,7 +300,7 @@ config CMDLINE | |||
292 | help | 300 | help |
293 | Supply command-line options at build time by entering them here. | 301 | Supply command-line options at build time by entering them here. |
294 | 302 | ||
295 | config CMDLINE_OVERRIDE | 303 | config CMDLINE_FORCE |
296 | bool "Built-in command line overrides bootloader arguments" | 304 | bool "Built-in command line overrides bootloader arguments" |
297 | depends on CMDLINE_BOOL | 305 | depends on CMDLINE_BOOL |
298 | help | 306 | help |
diff --git a/arch/riscv/Makefile b/arch/riscv/Makefile index 6719dd30ec5b..76e958a5414a 100644 --- a/arch/riscv/Makefile +++ b/arch/riscv/Makefile | |||
@@ -11,6 +11,9 @@ | |||
11 | LDFLAGS := | 11 | LDFLAGS := |
12 | OBJCOPYFLAGS := -O binary | 12 | OBJCOPYFLAGS := -O binary |
13 | LDFLAGS_vmlinux := | 13 | LDFLAGS_vmlinux := |
14 | ifeq ($(CONFIG_DYNAMIC_FTRACE),y) | ||
15 | LDFLAGS_vmlinux := --no-relax | ||
16 | endif | ||
14 | KBUILD_AFLAGS_MODULE += -fPIC | 17 | KBUILD_AFLAGS_MODULE += -fPIC |
15 | KBUILD_CFLAGS_MODULE += -fPIC | 18 | KBUILD_CFLAGS_MODULE += -fPIC |
16 | 19 | ||
@@ -56,6 +59,11 @@ endif | |||
56 | ifeq ($(CONFIG_CMODEL_MEDANY),y) | 59 | ifeq ($(CONFIG_CMODEL_MEDANY),y) |
57 | KBUILD_CFLAGS += -mcmodel=medany | 60 | KBUILD_CFLAGS += -mcmodel=medany |
58 | endif | 61 | endif |
62 | ifeq ($(CONFIG_MODULE_SECTIONS),y) | ||
63 | KBUILD_LDFLAGS_MODULE += -T $(srctree)/arch/riscv/kernel/module.lds | ||
64 | endif | ||
65 | |||
66 | KBUILD_CFLAGS_MODULE += $(call cc-option,-mno-relax) | ||
59 | 67 | ||
60 | # GCC versions that support the "-mstrict-align" option default to allowing | 68 | # GCC versions that support the "-mstrict-align" option default to allowing |
61 | # unaligned accesses. While unaligned accesses are explicitly allowed in the | 69 | # unaligned accesses. While unaligned accesses are explicitly allowed in the |
diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig index 47dacf06c679..bca0eee733b0 100644 --- a/arch/riscv/configs/defconfig +++ b/arch/riscv/configs/defconfig | |||
@@ -73,3 +73,5 @@ CONFIG_NFS_V4_2=y | |||
73 | CONFIG_ROOT_NFS=y | 73 | CONFIG_ROOT_NFS=y |
74 | # CONFIG_RCU_TRACE is not set | 74 | # CONFIG_RCU_TRACE is not set |
75 | CONFIG_CRYPTO_USER_API_HASH=y | 75 | CONFIG_CRYPTO_USER_API_HASH=y |
76 | CONFIG_MODULES=y | ||
77 | CONFIG_MODULE_UNLOAD=y | ||
diff --git a/arch/riscv/include/asm/atomic.h b/arch/riscv/include/asm/atomic.h index e65d1cd89e28..855115ace98c 100644 --- a/arch/riscv/include/asm/atomic.h +++ b/arch/riscv/include/asm/atomic.h | |||
@@ -24,6 +24,20 @@ | |||
24 | #include <asm/barrier.h> | 24 | #include <asm/barrier.h> |
25 | 25 | ||
26 | #define ATOMIC_INIT(i) { (i) } | 26 | #define ATOMIC_INIT(i) { (i) } |
27 | |||
28 | #define __atomic_op_acquire(op, args...) \ | ||
29 | ({ \ | ||
30 | typeof(op##_relaxed(args)) __ret = op##_relaxed(args); \ | ||
31 | __asm__ __volatile__(RISCV_ACQUIRE_BARRIER "" ::: "memory"); \ | ||
32 | __ret; \ | ||
33 | }) | ||
34 | |||
35 | #define __atomic_op_release(op, args...) \ | ||
36 | ({ \ | ||
37 | __asm__ __volatile__(RISCV_RELEASE_BARRIER "" ::: "memory"); \ | ||
38 | op##_relaxed(args); \ | ||
39 | }) | ||
40 | |||
27 | static __always_inline int atomic_read(const atomic_t *v) | 41 | static __always_inline int atomic_read(const atomic_t *v) |
28 | { | 42 | { |
29 | return READ_ONCE(v->counter); | 43 | return READ_ONCE(v->counter); |
@@ -50,22 +64,23 @@ static __always_inline void atomic64_set(atomic64_t *v, long i) | |||
50 | * have the AQ or RL bits set. These don't return anything, so there's only | 64 | * have the AQ or RL bits set. These don't return anything, so there's only |
51 | * one version to worry about. | 65 | * one version to worry about. |
52 | */ | 66 | */ |
53 | #define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix) \ | 67 | #define ATOMIC_OP(op, asm_op, I, asm_type, c_type, prefix) \ |
54 | static __always_inline void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ | 68 | static __always_inline \ |
55 | { \ | 69 | void atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ |
56 | __asm__ __volatile__ ( \ | 70 | { \ |
57 | "amo" #asm_op "." #asm_type " zero, %1, %0" \ | 71 | __asm__ __volatile__ ( \ |
58 | : "+A" (v->counter) \ | 72 | " amo" #asm_op "." #asm_type " zero, %1, %0" \ |
59 | : "r" (I) \ | 73 | : "+A" (v->counter) \ |
60 | : "memory"); \ | 74 | : "r" (I) \ |
61 | } | 75 | : "memory"); \ |
76 | } \ | ||
62 | 77 | ||
63 | #ifdef CONFIG_GENERIC_ATOMIC64 | 78 | #ifdef CONFIG_GENERIC_ATOMIC64 |
64 | #define ATOMIC_OPS(op, asm_op, I) \ | 79 | #define ATOMIC_OPS(op, asm_op, I) \ |
65 | ATOMIC_OP (op, asm_op, I, w, int, ) | 80 | ATOMIC_OP (op, asm_op, I, w, int, ) |
66 | #else | 81 | #else |
67 | #define ATOMIC_OPS(op, asm_op, I) \ | 82 | #define ATOMIC_OPS(op, asm_op, I) \ |
68 | ATOMIC_OP (op, asm_op, I, w, int, ) \ | 83 | ATOMIC_OP (op, asm_op, I, w, int, ) \ |
69 | ATOMIC_OP (op, asm_op, I, d, long, 64) | 84 | ATOMIC_OP (op, asm_op, I, d, long, 64) |
70 | #endif | 85 | #endif |
71 | 86 | ||
@@ -79,75 +94,115 @@ ATOMIC_OPS(xor, xor, i) | |||
79 | #undef ATOMIC_OPS | 94 | #undef ATOMIC_OPS |
80 | 95 | ||
81 | /* | 96 | /* |
82 | * Atomic ops that have ordered, relaxed, acquire, and relese variants. | 97 | * Atomic ops that have ordered, relaxed, acquire, and release variants. |
83 | * There's two flavors of these: the arithmatic ops have both fetch and return | 98 | * There's two flavors of these: the arithmatic ops have both fetch and return |
84 | * versions, while the logical ops only have fetch versions. | 99 | * versions, while the logical ops only have fetch versions. |
85 | */ | 100 | */ |
86 | #define ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, asm_type, c_type, prefix) \ | 101 | #define ATOMIC_FETCH_OP(op, asm_op, I, asm_type, c_type, prefix) \ |
87 | static __always_inline c_type atomic##prefix##_fetch_##op##c_or(c_type i, atomic##prefix##_t *v) \ | 102 | static __always_inline \ |
88 | { \ | 103 | c_type atomic##prefix##_fetch_##op##_relaxed(c_type i, \ |
89 | register c_type ret; \ | 104 | atomic##prefix##_t *v) \ |
90 | __asm__ __volatile__ ( \ | 105 | { \ |
91 | "amo" #asm_op "." #asm_type #asm_or " %1, %2, %0" \ | 106 | register c_type ret; \ |
92 | : "+A" (v->counter), "=r" (ret) \ | 107 | __asm__ __volatile__ ( \ |
93 | : "r" (I) \ | 108 | " amo" #asm_op "." #asm_type " %1, %2, %0" \ |
94 | : "memory"); \ | 109 | : "+A" (v->counter), "=r" (ret) \ |
95 | return ret; \ | 110 | : "r" (I) \ |
111 | : "memory"); \ | ||
112 | return ret; \ | ||
113 | } \ | ||
114 | static __always_inline \ | ||
115 | c_type atomic##prefix##_fetch_##op(c_type i, atomic##prefix##_t *v) \ | ||
116 | { \ | ||
117 | register c_type ret; \ | ||
118 | __asm__ __volatile__ ( \ | ||
119 | " amo" #asm_op "." #asm_type ".aqrl %1, %2, %0" \ | ||
120 | : "+A" (v->counter), "=r" (ret) \ | ||
121 | : "r" (I) \ | ||
122 | : "memory"); \ | ||
123 | return ret; \ | ||
96 | } | 124 | } |
97 | 125 | ||
98 | #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, asm_type, c_type, prefix) \ | 126 | #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_type, c_type, prefix) \ |
99 | static __always_inline c_type atomic##prefix##_##op##_return##c_or(c_type i, atomic##prefix##_t *v) \ | 127 | static __always_inline \ |
100 | { \ | 128 | c_type atomic##prefix##_##op##_return_relaxed(c_type i, \ |
101 | return atomic##prefix##_fetch_##op##c_or(i, v) c_op I; \ | 129 | atomic##prefix##_t *v) \ |
130 | { \ | ||
131 | return atomic##prefix##_fetch_##op##_relaxed(i, v) c_op I; \ | ||
132 | } \ | ||
133 | static __always_inline \ | ||
134 | c_type atomic##prefix##_##op##_return(c_type i, atomic##prefix##_t *v) \ | ||
135 | { \ | ||
136 | return atomic##prefix##_fetch_##op(i, v) c_op I; \ | ||
102 | } | 137 | } |
103 | 138 | ||
104 | #ifdef CONFIG_GENERIC_ATOMIC64 | 139 | #ifdef CONFIG_GENERIC_ATOMIC64 |
105 | #define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ | 140 | #define ATOMIC_OPS(op, asm_op, c_op, I) \ |
106 | ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, w, int, ) \ | 141 | ATOMIC_FETCH_OP( op, asm_op, I, w, int, ) \ |
107 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) | 142 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, w, int, ) |
108 | #else | 143 | #else |
109 | #define ATOMIC_OPS(op, asm_op, c_op, I, asm_or, c_or) \ | 144 | #define ATOMIC_OPS(op, asm_op, c_op, I) \ |
110 | ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, w, int, ) \ | 145 | ATOMIC_FETCH_OP( op, asm_op, I, w, int, ) \ |
111 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, w, int, ) \ | 146 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, w, int, ) \ |
112 | ATOMIC_FETCH_OP (op, asm_op, I, asm_or, c_or, d, long, 64) \ | 147 | ATOMIC_FETCH_OP( op, asm_op, I, d, long, 64) \ |
113 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, asm_or, c_or, d, long, 64) | 148 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, d, long, 64) |
114 | #endif | 149 | #endif |
115 | 150 | ||
116 | ATOMIC_OPS(add, add, +, i, , _relaxed) | 151 | ATOMIC_OPS(add, add, +, i) |
117 | ATOMIC_OPS(add, add, +, i, .aq , _acquire) | 152 | ATOMIC_OPS(sub, add, +, -i) |
118 | ATOMIC_OPS(add, add, +, i, .rl , _release) | 153 | |
119 | ATOMIC_OPS(add, add, +, i, .aqrl, ) | 154 | #define atomic_add_return_relaxed atomic_add_return_relaxed |
155 | #define atomic_sub_return_relaxed atomic_sub_return_relaxed | ||
156 | #define atomic_add_return atomic_add_return | ||
157 | #define atomic_sub_return atomic_sub_return | ||
120 | 158 | ||
121 | ATOMIC_OPS(sub, add, +, -i, , _relaxed) | 159 | #define atomic_fetch_add_relaxed atomic_fetch_add_relaxed |
122 | ATOMIC_OPS(sub, add, +, -i, .aq , _acquire) | 160 | #define atomic_fetch_sub_relaxed atomic_fetch_sub_relaxed |
123 | ATOMIC_OPS(sub, add, +, -i, .rl , _release) | 161 | #define atomic_fetch_add atomic_fetch_add |
124 | ATOMIC_OPS(sub, add, +, -i, .aqrl, ) | 162 | #define atomic_fetch_sub atomic_fetch_sub |
163 | |||
164 | #ifndef CONFIG_GENERIC_ATOMIC64 | ||
165 | #define atomic64_add_return_relaxed atomic64_add_return_relaxed | ||
166 | #define atomic64_sub_return_relaxed atomic64_sub_return_relaxed | ||
167 | #define atomic64_add_return atomic64_add_return | ||
168 | #define atomic64_sub_return atomic64_sub_return | ||
169 | |||
170 | #define atomic64_fetch_add_relaxed atomic64_fetch_add_relaxed | ||
171 | #define atomic64_fetch_sub_relaxed atomic64_fetch_sub_relaxed | ||
172 | #define atomic64_fetch_add atomic64_fetch_add | ||
173 | #define atomic64_fetch_sub atomic64_fetch_sub | ||
174 | #endif | ||
125 | 175 | ||
126 | #undef ATOMIC_OPS | 176 | #undef ATOMIC_OPS |
127 | 177 | ||
128 | #ifdef CONFIG_GENERIC_ATOMIC64 | 178 | #ifdef CONFIG_GENERIC_ATOMIC64 |
129 | #define ATOMIC_OPS(op, asm_op, I, asm_or, c_or) \ | 179 | #define ATOMIC_OPS(op, asm_op, I) \ |
130 | ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, w, int, ) | 180 | ATOMIC_FETCH_OP(op, asm_op, I, w, int, ) |
131 | #else | 181 | #else |
132 | #define ATOMIC_OPS(op, asm_op, I, asm_or, c_or) \ | 182 | #define ATOMIC_OPS(op, asm_op, I) \ |
133 | ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, w, int, ) \ | 183 | ATOMIC_FETCH_OP(op, asm_op, I, w, int, ) \ |
134 | ATOMIC_FETCH_OP(op, asm_op, I, asm_or, c_or, d, long, 64) | 184 | ATOMIC_FETCH_OP(op, asm_op, I, d, long, 64) |
135 | #endif | 185 | #endif |
136 | 186 | ||
137 | ATOMIC_OPS(and, and, i, , _relaxed) | 187 | ATOMIC_OPS(and, and, i) |
138 | ATOMIC_OPS(and, and, i, .aq , _acquire) | 188 | ATOMIC_OPS( or, or, i) |
139 | ATOMIC_OPS(and, and, i, .rl , _release) | 189 | ATOMIC_OPS(xor, xor, i) |
140 | ATOMIC_OPS(and, and, i, .aqrl, ) | ||
141 | 190 | ||
142 | ATOMIC_OPS( or, or, i, , _relaxed) | 191 | #define atomic_fetch_and_relaxed atomic_fetch_and_relaxed |
143 | ATOMIC_OPS( or, or, i, .aq , _acquire) | 192 | #define atomic_fetch_or_relaxed atomic_fetch_or_relaxed |
144 | ATOMIC_OPS( or, or, i, .rl , _release) | 193 | #define atomic_fetch_xor_relaxed atomic_fetch_xor_relaxed |
145 | ATOMIC_OPS( or, or, i, .aqrl, ) | 194 | #define atomic_fetch_and atomic_fetch_and |
195 | #define atomic_fetch_or atomic_fetch_or | ||
196 | #define atomic_fetch_xor atomic_fetch_xor | ||
146 | 197 | ||
147 | ATOMIC_OPS(xor, xor, i, , _relaxed) | 198 | #ifndef CONFIG_GENERIC_ATOMIC64 |
148 | ATOMIC_OPS(xor, xor, i, .aq , _acquire) | 199 | #define atomic64_fetch_and_relaxed atomic64_fetch_and_relaxed |
149 | ATOMIC_OPS(xor, xor, i, .rl , _release) | 200 | #define atomic64_fetch_or_relaxed atomic64_fetch_or_relaxed |
150 | ATOMIC_OPS(xor, xor, i, .aqrl, ) | 201 | #define atomic64_fetch_xor_relaxed atomic64_fetch_xor_relaxed |
202 | #define atomic64_fetch_and atomic64_fetch_and | ||
203 | #define atomic64_fetch_or atomic64_fetch_or | ||
204 | #define atomic64_fetch_xor atomic64_fetch_xor | ||
205 | #endif | ||
151 | 206 | ||
152 | #undef ATOMIC_OPS | 207 | #undef ATOMIC_OPS |
153 | 208 | ||
@@ -157,22 +212,24 @@ ATOMIC_OPS(xor, xor, i, .aqrl, ) | |||
157 | /* | 212 | /* |
158 | * The extra atomic operations that are constructed from one of the core | 213 | * The extra atomic operations that are constructed from one of the core |
159 | * AMO-based operations above (aside from sub, which is easier to fit above). | 214 | * AMO-based operations above (aside from sub, which is easier to fit above). |
160 | * These are required to perform a barrier, but they're OK this way because | 215 | * These are required to perform a full barrier, but they're OK this way |
161 | * atomic_*_return is also required to perform a barrier. | 216 | * because atomic_*_return is also required to perform a full barrier. |
217 | * | ||
162 | */ | 218 | */ |
163 | #define ATOMIC_OP(op, func_op, comp_op, I, c_type, prefix) \ | 219 | #define ATOMIC_OP(op, func_op, comp_op, I, c_type, prefix) \ |
164 | static __always_inline bool atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ | 220 | static __always_inline \ |
165 | { \ | 221 | bool atomic##prefix##_##op(c_type i, atomic##prefix##_t *v) \ |
166 | return atomic##prefix##_##func_op##_return(i, v) comp_op I; \ | 222 | { \ |
223 | return atomic##prefix##_##func_op##_return(i, v) comp_op I; \ | ||
167 | } | 224 | } |
168 | 225 | ||
169 | #ifdef CONFIG_GENERIC_ATOMIC64 | 226 | #ifdef CONFIG_GENERIC_ATOMIC64 |
170 | #define ATOMIC_OPS(op, func_op, comp_op, I) \ | 227 | #define ATOMIC_OPS(op, func_op, comp_op, I) \ |
171 | ATOMIC_OP (op, func_op, comp_op, I, int, ) | 228 | ATOMIC_OP(op, func_op, comp_op, I, int, ) |
172 | #else | 229 | #else |
173 | #define ATOMIC_OPS(op, func_op, comp_op, I) \ | 230 | #define ATOMIC_OPS(op, func_op, comp_op, I) \ |
174 | ATOMIC_OP (op, func_op, comp_op, I, int, ) \ | 231 | ATOMIC_OP(op, func_op, comp_op, I, int, ) \ |
175 | ATOMIC_OP (op, func_op, comp_op, I, long, 64) | 232 | ATOMIC_OP(op, func_op, comp_op, I, long, 64) |
176 | #endif | 233 | #endif |
177 | 234 | ||
178 | ATOMIC_OPS(add_and_test, add, ==, 0) | 235 | ATOMIC_OPS(add_and_test, add, ==, 0) |
@@ -182,51 +239,87 @@ ATOMIC_OPS(add_negative, add, <, 0) | |||
182 | #undef ATOMIC_OP | 239 | #undef ATOMIC_OP |
183 | #undef ATOMIC_OPS | 240 | #undef ATOMIC_OPS |
184 | 241 | ||
185 | #define ATOMIC_OP(op, func_op, I, c_type, prefix) \ | 242 | #define ATOMIC_OP(op, func_op, I, c_type, prefix) \ |
186 | static __always_inline void atomic##prefix##_##op(atomic##prefix##_t *v) \ | 243 | static __always_inline \ |
187 | { \ | 244 | void atomic##prefix##_##op(atomic##prefix##_t *v) \ |
188 | atomic##prefix##_##func_op(I, v); \ | 245 | { \ |
246 | atomic##prefix##_##func_op(I, v); \ | ||
189 | } | 247 | } |
190 | 248 | ||
191 | #define ATOMIC_FETCH_OP(op, func_op, I, c_type, prefix) \ | 249 | #define ATOMIC_FETCH_OP(op, func_op, I, c_type, prefix) \ |
192 | static __always_inline c_type atomic##prefix##_fetch_##op(atomic##prefix##_t *v) \ | 250 | static __always_inline \ |
193 | { \ | 251 | c_type atomic##prefix##_fetch_##op##_relaxed(atomic##prefix##_t *v) \ |
194 | return atomic##prefix##_fetch_##func_op(I, v); \ | 252 | { \ |
253 | return atomic##prefix##_fetch_##func_op##_relaxed(I, v); \ | ||
254 | } \ | ||
255 | static __always_inline \ | ||
256 | c_type atomic##prefix##_fetch_##op(atomic##prefix##_t *v) \ | ||
257 | { \ | ||
258 | return atomic##prefix##_fetch_##func_op(I, v); \ | ||
195 | } | 259 | } |
196 | 260 | ||
197 | #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, c_type, prefix) \ | 261 | #define ATOMIC_OP_RETURN(op, asm_op, c_op, I, c_type, prefix) \ |
198 | static __always_inline c_type atomic##prefix##_##op##_return(atomic##prefix##_t *v) \ | 262 | static __always_inline \ |
199 | { \ | 263 | c_type atomic##prefix##_##op##_return_relaxed(atomic##prefix##_t *v) \ |
200 | return atomic##prefix##_fetch_##op(v) c_op I; \ | 264 | { \ |
265 | return atomic##prefix##_fetch_##op##_relaxed(v) c_op I; \ | ||
266 | } \ | ||
267 | static __always_inline \ | ||
268 | c_type atomic##prefix##_##op##_return(atomic##prefix##_t *v) \ | ||
269 | { \ | ||
270 | return atomic##prefix##_fetch_##op(v) c_op I; \ | ||
201 | } | 271 | } |
202 | 272 | ||
203 | #ifdef CONFIG_GENERIC_ATOMIC64 | 273 | #ifdef CONFIG_GENERIC_ATOMIC64 |
204 | #define ATOMIC_OPS(op, asm_op, c_op, I) \ | 274 | #define ATOMIC_OPS(op, asm_op, c_op, I) \ |
205 | ATOMIC_OP (op, asm_op, I, int, ) \ | 275 | ATOMIC_OP( op, asm_op, I, int, ) \ |
206 | ATOMIC_FETCH_OP (op, asm_op, I, int, ) \ | 276 | ATOMIC_FETCH_OP( op, asm_op, I, int, ) \ |
207 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) | 277 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) |
208 | #else | 278 | #else |
209 | #define ATOMIC_OPS(op, asm_op, c_op, I) \ | 279 | #define ATOMIC_OPS(op, asm_op, c_op, I) \ |
210 | ATOMIC_OP (op, asm_op, I, int, ) \ | 280 | ATOMIC_OP( op, asm_op, I, int, ) \ |
211 | ATOMIC_FETCH_OP (op, asm_op, I, int, ) \ | 281 | ATOMIC_FETCH_OP( op, asm_op, I, int, ) \ |
212 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) \ | 282 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, int, ) \ |
213 | ATOMIC_OP (op, asm_op, I, long, 64) \ | 283 | ATOMIC_OP( op, asm_op, I, long, 64) \ |
214 | ATOMIC_FETCH_OP (op, asm_op, I, long, 64) \ | 284 | ATOMIC_FETCH_OP( op, asm_op, I, long, 64) \ |
215 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, long, 64) | 285 | ATOMIC_OP_RETURN(op, asm_op, c_op, I, long, 64) |
216 | #endif | 286 | #endif |
217 | 287 | ||
218 | ATOMIC_OPS(inc, add, +, 1) | 288 | ATOMIC_OPS(inc, add, +, 1) |
219 | ATOMIC_OPS(dec, add, +, -1) | 289 | ATOMIC_OPS(dec, add, +, -1) |
220 | 290 | ||
291 | #define atomic_inc_return_relaxed atomic_inc_return_relaxed | ||
292 | #define atomic_dec_return_relaxed atomic_dec_return_relaxed | ||
293 | #define atomic_inc_return atomic_inc_return | ||
294 | #define atomic_dec_return atomic_dec_return | ||
295 | |||
296 | #define atomic_fetch_inc_relaxed atomic_fetch_inc_relaxed | ||
297 | #define atomic_fetch_dec_relaxed atomic_fetch_dec_relaxed | ||
298 | #define atomic_fetch_inc atomic_fetch_inc | ||
299 | #define atomic_fetch_dec atomic_fetch_dec | ||
300 | |||
301 | #ifndef CONFIG_GENERIC_ATOMIC64 | ||
302 | #define atomic64_inc_return_relaxed atomic64_inc_return_relaxed | ||
303 | #define atomic64_dec_return_relaxed atomic64_dec_return_relaxed | ||
304 | #define atomic64_inc_return atomic64_inc_return | ||
305 | #define atomic64_dec_return atomic64_dec_return | ||
306 | |||
307 | #define atomic64_fetch_inc_relaxed atomic64_fetch_inc_relaxed | ||
308 | #define atomic64_fetch_dec_relaxed atomic64_fetch_dec_relaxed | ||
309 | #define atomic64_fetch_inc atomic64_fetch_inc | ||
310 | #define atomic64_fetch_dec atomic64_fetch_dec | ||
311 | #endif | ||
312 | |||
221 | #undef ATOMIC_OPS | 313 | #undef ATOMIC_OPS |
222 | #undef ATOMIC_OP | 314 | #undef ATOMIC_OP |
223 | #undef ATOMIC_FETCH_OP | 315 | #undef ATOMIC_FETCH_OP |
224 | #undef ATOMIC_OP_RETURN | 316 | #undef ATOMIC_OP_RETURN |
225 | 317 | ||
226 | #define ATOMIC_OP(op, func_op, comp_op, I, prefix) \ | 318 | #define ATOMIC_OP(op, func_op, comp_op, I, prefix) \ |
227 | static __always_inline bool atomic##prefix##_##op(atomic##prefix##_t *v) \ | 319 | static __always_inline \ |
228 | { \ | 320 | bool atomic##prefix##_##op(atomic##prefix##_t *v) \ |
229 | return atomic##prefix##_##func_op##_return(v) comp_op I; \ | 321 | { \ |
322 | return atomic##prefix##_##func_op##_return(v) comp_op I; \ | ||
230 | } | 323 | } |
231 | 324 | ||
232 | ATOMIC_OP(inc_and_test, inc, ==, 0, ) | 325 | ATOMIC_OP(inc_and_test, inc, ==, 0, ) |
@@ -238,19 +331,19 @@ ATOMIC_OP(dec_and_test, dec, ==, 0, 64) | |||
238 | 331 | ||
239 | #undef ATOMIC_OP | 332 | #undef ATOMIC_OP |
240 | 333 | ||
241 | /* This is required to provide a barrier on success. */ | 334 | /* This is required to provide a full barrier on success. */ |
242 | static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) | 335 | static __always_inline int __atomic_add_unless(atomic_t *v, int a, int u) |
243 | { | 336 | { |
244 | int prev, rc; | 337 | int prev, rc; |
245 | 338 | ||
246 | __asm__ __volatile__ ( | 339 | __asm__ __volatile__ ( |
247 | "0:\n\t" | 340 | "0: lr.w %[p], %[c]\n" |
248 | "lr.w.aqrl %[p], %[c]\n\t" | 341 | " beq %[p], %[u], 1f\n" |
249 | "beq %[p], %[u], 1f\n\t" | 342 | " add %[rc], %[p], %[a]\n" |
250 | "add %[rc], %[p], %[a]\n\t" | 343 | " sc.w.rl %[rc], %[rc], %[c]\n" |
251 | "sc.w.aqrl %[rc], %[rc], %[c]\n\t" | 344 | " bnez %[rc], 0b\n" |
252 | "bnez %[rc], 0b\n\t" | 345 | " fence rw, rw\n" |
253 | "1:" | 346 | "1:\n" |
254 | : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) | 347 | : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) |
255 | : [a]"r" (a), [u]"r" (u) | 348 | : [a]"r" (a), [u]"r" (u) |
256 | : "memory"); | 349 | : "memory"); |
@@ -263,13 +356,13 @@ static __always_inline long __atomic64_add_unless(atomic64_t *v, long a, long u) | |||
263 | long prev, rc; | 356 | long prev, rc; |
264 | 357 | ||
265 | __asm__ __volatile__ ( | 358 | __asm__ __volatile__ ( |
266 | "0:\n\t" | 359 | "0: lr.d %[p], %[c]\n" |
267 | "lr.d.aqrl %[p], %[c]\n\t" | 360 | " beq %[p], %[u], 1f\n" |
268 | "beq %[p], %[u], 1f\n\t" | 361 | " add %[rc], %[p], %[a]\n" |
269 | "add %[rc], %[p], %[a]\n\t" | 362 | " sc.d.rl %[rc], %[rc], %[c]\n" |
270 | "sc.d.aqrl %[rc], %[rc], %[c]\n\t" | 363 | " bnez %[rc], 0b\n" |
271 | "bnez %[rc], 0b\n\t" | 364 | " fence rw, rw\n" |
272 | "1:" | 365 | "1:\n" |
273 | : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) | 366 | : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) |
274 | : [a]"r" (a), [u]"r" (u) | 367 | : [a]"r" (a), [u]"r" (u) |
275 | : "memory"); | 368 | : "memory"); |
@@ -300,37 +393,63 @@ static __always_inline long atomic64_inc_not_zero(atomic64_t *v) | |||
300 | 393 | ||
301 | /* | 394 | /* |
302 | * atomic_{cmp,}xchg is required to have exactly the same ordering semantics as | 395 | * atomic_{cmp,}xchg is required to have exactly the same ordering semantics as |
303 | * {cmp,}xchg and the operations that return, so they need a barrier. | 396 | * {cmp,}xchg and the operations that return, so they need a full barrier. |
304 | */ | ||
305 | /* | ||
306 | * FIXME: atomic_cmpxchg_{acquire,release,relaxed} are all implemented by | ||
307 | * assigning the same barrier to both the LR and SC operations, but that might | ||
308 | * not make any sense. We're waiting on a memory model specification to | ||
309 | * determine exactly what the right thing to do is here. | ||
310 | */ | 397 | */ |
311 | #define ATOMIC_OP(c_t, prefix, c_or, size, asm_or) \ | 398 | #define ATOMIC_OP(c_t, prefix, size) \ |
312 | static __always_inline c_t atomic##prefix##_cmpxchg##c_or(atomic##prefix##_t *v, c_t o, c_t n) \ | 399 | static __always_inline \ |
313 | { \ | 400 | c_t atomic##prefix##_xchg_relaxed(atomic##prefix##_t *v, c_t n) \ |
314 | return __cmpxchg(&(v->counter), o, n, size, asm_or, asm_or); \ | 401 | { \ |
315 | } \ | 402 | return __xchg_relaxed(&(v->counter), n, size); \ |
316 | static __always_inline c_t atomic##prefix##_xchg##c_or(atomic##prefix##_t *v, c_t n) \ | 403 | } \ |
317 | { \ | 404 | static __always_inline \ |
318 | return __xchg(n, &(v->counter), size, asm_or); \ | 405 | c_t atomic##prefix##_xchg_acquire(atomic##prefix##_t *v, c_t n) \ |
406 | { \ | ||
407 | return __xchg_acquire(&(v->counter), n, size); \ | ||
408 | } \ | ||
409 | static __always_inline \ | ||
410 | c_t atomic##prefix##_xchg_release(atomic##prefix##_t *v, c_t n) \ | ||
411 | { \ | ||
412 | return __xchg_release(&(v->counter), n, size); \ | ||
413 | } \ | ||
414 | static __always_inline \ | ||
415 | c_t atomic##prefix##_xchg(atomic##prefix##_t *v, c_t n) \ | ||
416 | { \ | ||
417 | return __xchg(&(v->counter), n, size); \ | ||
418 | } \ | ||
419 | static __always_inline \ | ||
420 | c_t atomic##prefix##_cmpxchg_relaxed(atomic##prefix##_t *v, \ | ||
421 | c_t o, c_t n) \ | ||
422 | { \ | ||
423 | return __cmpxchg_relaxed(&(v->counter), o, n, size); \ | ||
424 | } \ | ||
425 | static __always_inline \ | ||
426 | c_t atomic##prefix##_cmpxchg_acquire(atomic##prefix##_t *v, \ | ||
427 | c_t o, c_t n) \ | ||
428 | { \ | ||
429 | return __cmpxchg_acquire(&(v->counter), o, n, size); \ | ||
430 | } \ | ||
431 | static __always_inline \ | ||
432 | c_t atomic##prefix##_cmpxchg_release(atomic##prefix##_t *v, \ | ||
433 | c_t o, c_t n) \ | ||
434 | { \ | ||
435 | return __cmpxchg_release(&(v->counter), o, n, size); \ | ||
436 | } \ | ||
437 | static __always_inline \ | ||
438 | c_t atomic##prefix##_cmpxchg(atomic##prefix##_t *v, c_t o, c_t n) \ | ||
439 | { \ | ||
440 | return __cmpxchg(&(v->counter), o, n, size); \ | ||
319 | } | 441 | } |
320 | 442 | ||
321 | #ifdef CONFIG_GENERIC_ATOMIC64 | 443 | #ifdef CONFIG_GENERIC_ATOMIC64 |
322 | #define ATOMIC_OPS(c_or, asm_or) \ | 444 | #define ATOMIC_OPS() \ |
323 | ATOMIC_OP( int, , c_or, 4, asm_or) | 445 | ATOMIC_OP( int, , 4) |
324 | #else | 446 | #else |
325 | #define ATOMIC_OPS(c_or, asm_or) \ | 447 | #define ATOMIC_OPS() \ |
326 | ATOMIC_OP( int, , c_or, 4, asm_or) \ | 448 | ATOMIC_OP( int, , 4) \ |
327 | ATOMIC_OP(long, 64, c_or, 8, asm_or) | 449 | ATOMIC_OP(long, 64, 8) |
328 | #endif | 450 | #endif |
329 | 451 | ||
330 | ATOMIC_OPS( , .aqrl) | 452 | ATOMIC_OPS() |
331 | ATOMIC_OPS(_acquire, .aq) | ||
332 | ATOMIC_OPS(_release, .rl) | ||
333 | ATOMIC_OPS(_relaxed, ) | ||
334 | 453 | ||
335 | #undef ATOMIC_OPS | 454 | #undef ATOMIC_OPS |
336 | #undef ATOMIC_OP | 455 | #undef ATOMIC_OP |
@@ -340,13 +459,13 @@ static __always_inline int atomic_sub_if_positive(atomic_t *v, int offset) | |||
340 | int prev, rc; | 459 | int prev, rc; |
341 | 460 | ||
342 | __asm__ __volatile__ ( | 461 | __asm__ __volatile__ ( |
343 | "0:\n\t" | 462 | "0: lr.w %[p], %[c]\n" |
344 | "lr.w.aqrl %[p], %[c]\n\t" | 463 | " sub %[rc], %[p], %[o]\n" |
345 | "sub %[rc], %[p], %[o]\n\t" | 464 | " bltz %[rc], 1f\n" |
346 | "bltz %[rc], 1f\n\t" | 465 | " sc.w.rl %[rc], %[rc], %[c]\n" |
347 | "sc.w.aqrl %[rc], %[rc], %[c]\n\t" | 466 | " bnez %[rc], 0b\n" |
348 | "bnez %[rc], 0b\n\t" | 467 | " fence rw, rw\n" |
349 | "1:" | 468 | "1:\n" |
350 | : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) | 469 | : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) |
351 | : [o]"r" (offset) | 470 | : [o]"r" (offset) |
352 | : "memory"); | 471 | : "memory"); |
@@ -361,13 +480,13 @@ static __always_inline long atomic64_sub_if_positive(atomic64_t *v, int offset) | |||
361 | long prev, rc; | 480 | long prev, rc; |
362 | 481 | ||
363 | __asm__ __volatile__ ( | 482 | __asm__ __volatile__ ( |
364 | "0:\n\t" | 483 | "0: lr.d %[p], %[c]\n" |
365 | "lr.d.aqrl %[p], %[c]\n\t" | 484 | " sub %[rc], %[p], %[o]\n" |
366 | "sub %[rc], %[p], %[o]\n\t" | 485 | " bltz %[rc], 1f\n" |
367 | "bltz %[rc], 1f\n\t" | 486 | " sc.d.rl %[rc], %[rc], %[c]\n" |
368 | "sc.d.aqrl %[rc], %[rc], %[c]\n\t" | 487 | " bnez %[rc], 0b\n" |
369 | "bnez %[rc], 0b\n\t" | 488 | " fence rw, rw\n" |
370 | "1:" | 489 | "1:\n" |
371 | : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) | 490 | : [p]"=&r" (prev), [rc]"=&r" (rc), [c]"+A" (v->counter) |
372 | : [o]"r" (offset) | 491 | : [o]"r" (offset) |
373 | : "memory"); | 492 | : "memory"); |
diff --git a/arch/riscv/include/asm/barrier.h b/arch/riscv/include/asm/barrier.h index 5510366d169a..d4628e4b3a5e 100644 --- a/arch/riscv/include/asm/barrier.h +++ b/arch/riscv/include/asm/barrier.h | |||
@@ -38,6 +38,21 @@ | |||
38 | #define __smp_rmb() RISCV_FENCE(r,r) | 38 | #define __smp_rmb() RISCV_FENCE(r,r) |
39 | #define __smp_wmb() RISCV_FENCE(w,w) | 39 | #define __smp_wmb() RISCV_FENCE(w,w) |
40 | 40 | ||
41 | #define __smp_store_release(p, v) \ | ||
42 | do { \ | ||
43 | compiletime_assert_atomic_type(*p); \ | ||
44 | RISCV_FENCE(rw,w); \ | ||
45 | WRITE_ONCE(*p, v); \ | ||
46 | } while (0) | ||
47 | |||
48 | #define __smp_load_acquire(p) \ | ||
49 | ({ \ | ||
50 | typeof(*p) ___p1 = READ_ONCE(*p); \ | ||
51 | compiletime_assert_atomic_type(*p); \ | ||
52 | RISCV_FENCE(r,rw); \ | ||
53 | ___p1; \ | ||
54 | }) | ||
55 | |||
41 | /* | 56 | /* |
42 | * This is a very specific barrier: it's currently only used in two places in | 57 | * This is a very specific barrier: it's currently only used in two places in |
43 | * the kernel, both in the scheduler. See include/linux/spinlock.h for the two | 58 | * the kernel, both in the scheduler. See include/linux/spinlock.h for the two |
diff --git a/arch/riscv/include/asm/cmpxchg.h b/arch/riscv/include/asm/cmpxchg.h index db249dbc7b97..c12833f7b6bd 100644 --- a/arch/riscv/include/asm/cmpxchg.h +++ b/arch/riscv/include/asm/cmpxchg.h | |||
@@ -17,45 +17,153 @@ | |||
17 | #include <linux/bug.h> | 17 | #include <linux/bug.h> |
18 | 18 | ||
19 | #include <asm/barrier.h> | 19 | #include <asm/barrier.h> |
20 | #include <asm/fence.h> | ||
20 | 21 | ||
21 | #define __xchg(new, ptr, size, asm_or) \ | 22 | #define __xchg_relaxed(ptr, new, size) \ |
22 | ({ \ | 23 | ({ \ |
23 | __typeof__(ptr) __ptr = (ptr); \ | 24 | __typeof__(ptr) __ptr = (ptr); \ |
24 | __typeof__(new) __new = (new); \ | 25 | __typeof__(new) __new = (new); \ |
25 | __typeof__(*(ptr)) __ret; \ | 26 | __typeof__(*(ptr)) __ret; \ |
26 | switch (size) { \ | 27 | switch (size) { \ |
27 | case 4: \ | 28 | case 4: \ |
28 | __asm__ __volatile__ ( \ | 29 | __asm__ __volatile__ ( \ |
29 | "amoswap.w" #asm_or " %0, %2, %1" \ | 30 | " amoswap.w %0, %2, %1\n" \ |
30 | : "=r" (__ret), "+A" (*__ptr) \ | 31 | : "=r" (__ret), "+A" (*__ptr) \ |
31 | : "r" (__new) \ | 32 | : "r" (__new) \ |
32 | : "memory"); \ | 33 | : "memory"); \ |
33 | break; \ | 34 | break; \ |
34 | case 8: \ | 35 | case 8: \ |
35 | __asm__ __volatile__ ( \ | 36 | __asm__ __volatile__ ( \ |
36 | "amoswap.d" #asm_or " %0, %2, %1" \ | 37 | " amoswap.d %0, %2, %1\n" \ |
37 | : "=r" (__ret), "+A" (*__ptr) \ | 38 | : "=r" (__ret), "+A" (*__ptr) \ |
38 | : "r" (__new) \ | 39 | : "r" (__new) \ |
39 | : "memory"); \ | 40 | : "memory"); \ |
40 | break; \ | 41 | break; \ |
41 | default: \ | 42 | default: \ |
42 | BUILD_BUG(); \ | 43 | BUILD_BUG(); \ |
43 | } \ | 44 | } \ |
44 | __ret; \ | 45 | __ret; \ |
45 | }) | 46 | }) |
46 | 47 | ||
47 | #define xchg(ptr, x) (__xchg((x), (ptr), sizeof(*(ptr)), .aqrl)) | 48 | #define xchg_relaxed(ptr, x) \ |
48 | 49 | ({ \ | |
49 | #define xchg32(ptr, x) \ | 50 | __typeof__(*(ptr)) _x_ = (x); \ |
50 | ({ \ | 51 | (__typeof__(*(ptr))) __xchg_relaxed((ptr), \ |
51 | BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ | 52 | _x_, sizeof(*(ptr))); \ |
52 | xchg((ptr), (x)); \ | 53 | }) |
53 | }) | 54 | |
54 | 55 | #define __xchg_acquire(ptr, new, size) \ | |
55 | #define xchg64(ptr, x) \ | 56 | ({ \ |
56 | ({ \ | 57 | __typeof__(ptr) __ptr = (ptr); \ |
57 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | 58 | __typeof__(new) __new = (new); \ |
58 | xchg((ptr), (x)); \ | 59 | __typeof__(*(ptr)) __ret; \ |
60 | switch (size) { \ | ||
61 | case 4: \ | ||
62 | __asm__ __volatile__ ( \ | ||
63 | " amoswap.w %0, %2, %1\n" \ | ||
64 | RISCV_ACQUIRE_BARRIER \ | ||
65 | : "=r" (__ret), "+A" (*__ptr) \ | ||
66 | : "r" (__new) \ | ||
67 | : "memory"); \ | ||
68 | break; \ | ||
69 | case 8: \ | ||
70 | __asm__ __volatile__ ( \ | ||
71 | " amoswap.d %0, %2, %1\n" \ | ||
72 | RISCV_ACQUIRE_BARRIER \ | ||
73 | : "=r" (__ret), "+A" (*__ptr) \ | ||
74 | : "r" (__new) \ | ||
75 | : "memory"); \ | ||
76 | break; \ | ||
77 | default: \ | ||
78 | BUILD_BUG(); \ | ||
79 | } \ | ||
80 | __ret; \ | ||
81 | }) | ||
82 | |||
83 | #define xchg_acquire(ptr, x) \ | ||
84 | ({ \ | ||
85 | __typeof__(*(ptr)) _x_ = (x); \ | ||
86 | (__typeof__(*(ptr))) __xchg_acquire((ptr), \ | ||
87 | _x_, sizeof(*(ptr))); \ | ||
88 | }) | ||
89 | |||
90 | #define __xchg_release(ptr, new, size) \ | ||
91 | ({ \ | ||
92 | __typeof__(ptr) __ptr = (ptr); \ | ||
93 | __typeof__(new) __new = (new); \ | ||
94 | __typeof__(*(ptr)) __ret; \ | ||
95 | switch (size) { \ | ||
96 | case 4: \ | ||
97 | __asm__ __volatile__ ( \ | ||
98 | RISCV_RELEASE_BARRIER \ | ||
99 | " amoswap.w %0, %2, %1\n" \ | ||
100 | : "=r" (__ret), "+A" (*__ptr) \ | ||
101 | : "r" (__new) \ | ||
102 | : "memory"); \ | ||
103 | break; \ | ||
104 | case 8: \ | ||
105 | __asm__ __volatile__ ( \ | ||
106 | RISCV_RELEASE_BARRIER \ | ||
107 | " amoswap.d %0, %2, %1\n" \ | ||
108 | : "=r" (__ret), "+A" (*__ptr) \ | ||
109 | : "r" (__new) \ | ||
110 | : "memory"); \ | ||
111 | break; \ | ||
112 | default: \ | ||
113 | BUILD_BUG(); \ | ||
114 | } \ | ||
115 | __ret; \ | ||
116 | }) | ||
117 | |||
118 | #define xchg_release(ptr, x) \ | ||
119 | ({ \ | ||
120 | __typeof__(*(ptr)) _x_ = (x); \ | ||
121 | (__typeof__(*(ptr))) __xchg_release((ptr), \ | ||
122 | _x_, sizeof(*(ptr))); \ | ||
123 | }) | ||
124 | |||
125 | #define __xchg(ptr, new, size) \ | ||
126 | ({ \ | ||
127 | __typeof__(ptr) __ptr = (ptr); \ | ||
128 | __typeof__(new) __new = (new); \ | ||
129 | __typeof__(*(ptr)) __ret; \ | ||
130 | switch (size) { \ | ||
131 | case 4: \ | ||
132 | __asm__ __volatile__ ( \ | ||
133 | " amoswap.w.aqrl %0, %2, %1\n" \ | ||
134 | : "=r" (__ret), "+A" (*__ptr) \ | ||
135 | : "r" (__new) \ | ||
136 | : "memory"); \ | ||
137 | break; \ | ||
138 | case 8: \ | ||
139 | __asm__ __volatile__ ( \ | ||
140 | " amoswap.d.aqrl %0, %2, %1\n" \ | ||
141 | : "=r" (__ret), "+A" (*__ptr) \ | ||
142 | : "r" (__new) \ | ||
143 | : "memory"); \ | ||
144 | break; \ | ||
145 | default: \ | ||
146 | BUILD_BUG(); \ | ||
147 | } \ | ||
148 | __ret; \ | ||
149 | }) | ||
150 | |||
151 | #define xchg(ptr, x) \ | ||
152 | ({ \ | ||
153 | __typeof__(*(ptr)) _x_ = (x); \ | ||
154 | (__typeof__(*(ptr))) __xchg((ptr), _x_, sizeof(*(ptr))); \ | ||
155 | }) | ||
156 | |||
157 | #define xchg32(ptr, x) \ | ||
158 | ({ \ | ||
159 | BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ | ||
160 | xchg((ptr), (x)); \ | ||
161 | }) | ||
162 | |||
163 | #define xchg64(ptr, x) \ | ||
164 | ({ \ | ||
165 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | ||
166 | xchg((ptr), (x)); \ | ||
59 | }) | 167 | }) |
60 | 168 | ||
61 | /* | 169 | /* |
@@ -63,7 +171,51 @@ | |||
63 | * store NEW in MEM. Return the initial value in MEM. Success is | 171 | * store NEW in MEM. Return the initial value in MEM. Success is |
64 | * indicated by comparing RETURN with OLD. | 172 | * indicated by comparing RETURN with OLD. |
65 | */ | 173 | */ |
66 | #define __cmpxchg(ptr, old, new, size, lrb, scb) \ | 174 | #define __cmpxchg_relaxed(ptr, old, new, size) \ |
175 | ({ \ | ||
176 | __typeof__(ptr) __ptr = (ptr); \ | ||
177 | __typeof__(*(ptr)) __old = (old); \ | ||
178 | __typeof__(*(ptr)) __new = (new); \ | ||
179 | __typeof__(*(ptr)) __ret; \ | ||
180 | register unsigned int __rc; \ | ||
181 | switch (size) { \ | ||
182 | case 4: \ | ||
183 | __asm__ __volatile__ ( \ | ||
184 | "0: lr.w %0, %2\n" \ | ||
185 | " bne %0, %z3, 1f\n" \ | ||
186 | " sc.w %1, %z4, %2\n" \ | ||
187 | " bnez %1, 0b\n" \ | ||
188 | "1:\n" \ | ||
189 | : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ | ||
190 | : "rJ" (__old), "rJ" (__new) \ | ||
191 | : "memory"); \ | ||
192 | break; \ | ||
193 | case 8: \ | ||
194 | __asm__ __volatile__ ( \ | ||
195 | "0: lr.d %0, %2\n" \ | ||
196 | " bne %0, %z3, 1f\n" \ | ||
197 | " sc.d %1, %z4, %2\n" \ | ||
198 | " bnez %1, 0b\n" \ | ||
199 | "1:\n" \ | ||
200 | : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ | ||
201 | : "rJ" (__old), "rJ" (__new) \ | ||
202 | : "memory"); \ | ||
203 | break; \ | ||
204 | default: \ | ||
205 | BUILD_BUG(); \ | ||
206 | } \ | ||
207 | __ret; \ | ||
208 | }) | ||
209 | |||
210 | #define cmpxchg_relaxed(ptr, o, n) \ | ||
211 | ({ \ | ||
212 | __typeof__(*(ptr)) _o_ = (o); \ | ||
213 | __typeof__(*(ptr)) _n_ = (n); \ | ||
214 | (__typeof__(*(ptr))) __cmpxchg_relaxed((ptr), \ | ||
215 | _o_, _n_, sizeof(*(ptr))); \ | ||
216 | }) | ||
217 | |||
218 | #define __cmpxchg_acquire(ptr, old, new, size) \ | ||
67 | ({ \ | 219 | ({ \ |
68 | __typeof__(ptr) __ptr = (ptr); \ | 220 | __typeof__(ptr) __ptr = (ptr); \ |
69 | __typeof__(*(ptr)) __old = (old); \ | 221 | __typeof__(*(ptr)) __old = (old); \ |
@@ -73,24 +225,24 @@ | |||
73 | switch (size) { \ | 225 | switch (size) { \ |
74 | case 4: \ | 226 | case 4: \ |
75 | __asm__ __volatile__ ( \ | 227 | __asm__ __volatile__ ( \ |
76 | "0:" \ | 228 | "0: lr.w %0, %2\n" \ |
77 | "lr.w" #scb " %0, %2\n" \ | 229 | " bne %0, %z3, 1f\n" \ |
78 | "bne %0, %z3, 1f\n" \ | 230 | " sc.w %1, %z4, %2\n" \ |
79 | "sc.w" #lrb " %1, %z4, %2\n" \ | 231 | " bnez %1, 0b\n" \ |
80 | "bnez %1, 0b\n" \ | 232 | RISCV_ACQUIRE_BARRIER \ |
81 | "1:" \ | 233 | "1:\n" \ |
82 | : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ | 234 | : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ |
83 | : "rJ" (__old), "rJ" (__new) \ | 235 | : "rJ" (__old), "rJ" (__new) \ |
84 | : "memory"); \ | 236 | : "memory"); \ |
85 | break; \ | 237 | break; \ |
86 | case 8: \ | 238 | case 8: \ |
87 | __asm__ __volatile__ ( \ | 239 | __asm__ __volatile__ ( \ |
88 | "0:" \ | 240 | "0: lr.d %0, %2\n" \ |
89 | "lr.d" #scb " %0, %2\n" \ | 241 | " bne %0, %z3, 1f\n" \ |
90 | "bne %0, %z3, 1f\n" \ | 242 | " sc.d %1, %z4, %2\n" \ |
91 | "sc.d" #lrb " %1, %z4, %2\n" \ | 243 | " bnez %1, 0b\n" \ |
92 | "bnez %1, 0b\n" \ | 244 | RISCV_ACQUIRE_BARRIER \ |
93 | "1:" \ | 245 | "1:\n" \ |
94 | : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ | 246 | : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ |
95 | : "rJ" (__old), "rJ" (__new) \ | 247 | : "rJ" (__old), "rJ" (__new) \ |
96 | : "memory"); \ | 248 | : "memory"); \ |
@@ -101,34 +253,131 @@ | |||
101 | __ret; \ | 253 | __ret; \ |
102 | }) | 254 | }) |
103 | 255 | ||
104 | #define cmpxchg(ptr, o, n) \ | 256 | #define cmpxchg_acquire(ptr, o, n) \ |
105 | (__cmpxchg((ptr), (o), (n), sizeof(*(ptr)), .aqrl, .aqrl)) | 257 | ({ \ |
258 | __typeof__(*(ptr)) _o_ = (o); \ | ||
259 | __typeof__(*(ptr)) _n_ = (n); \ | ||
260 | (__typeof__(*(ptr))) __cmpxchg_acquire((ptr), \ | ||
261 | _o_, _n_, sizeof(*(ptr))); \ | ||
262 | }) | ||
106 | 263 | ||
107 | #define cmpxchg_local(ptr, o, n) \ | 264 | #define __cmpxchg_release(ptr, old, new, size) \ |
108 | (__cmpxchg((ptr), (o), (n), sizeof(*(ptr)), , )) | 265 | ({ \ |
266 | __typeof__(ptr) __ptr = (ptr); \ | ||
267 | __typeof__(*(ptr)) __old = (old); \ | ||
268 | __typeof__(*(ptr)) __new = (new); \ | ||
269 | __typeof__(*(ptr)) __ret; \ | ||
270 | register unsigned int __rc; \ | ||
271 | switch (size) { \ | ||
272 | case 4: \ | ||
273 | __asm__ __volatile__ ( \ | ||
274 | RISCV_RELEASE_BARRIER \ | ||
275 | "0: lr.w %0, %2\n" \ | ||
276 | " bne %0, %z3, 1f\n" \ | ||
277 | " sc.w %1, %z4, %2\n" \ | ||
278 | " bnez %1, 0b\n" \ | ||
279 | "1:\n" \ | ||
280 | : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ | ||
281 | : "rJ" (__old), "rJ" (__new) \ | ||
282 | : "memory"); \ | ||
283 | break; \ | ||
284 | case 8: \ | ||
285 | __asm__ __volatile__ ( \ | ||
286 | RISCV_RELEASE_BARRIER \ | ||
287 | "0: lr.d %0, %2\n" \ | ||
288 | " bne %0, %z3, 1f\n" \ | ||
289 | " sc.d %1, %z4, %2\n" \ | ||
290 | " bnez %1, 0b\n" \ | ||
291 | "1:\n" \ | ||
292 | : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ | ||
293 | : "rJ" (__old), "rJ" (__new) \ | ||
294 | : "memory"); \ | ||
295 | break; \ | ||
296 | default: \ | ||
297 | BUILD_BUG(); \ | ||
298 | } \ | ||
299 | __ret; \ | ||
300 | }) | ||
301 | |||
302 | #define cmpxchg_release(ptr, o, n) \ | ||
303 | ({ \ | ||
304 | __typeof__(*(ptr)) _o_ = (o); \ | ||
305 | __typeof__(*(ptr)) _n_ = (n); \ | ||
306 | (__typeof__(*(ptr))) __cmpxchg_release((ptr), \ | ||
307 | _o_, _n_, sizeof(*(ptr))); \ | ||
308 | }) | ||
309 | |||
310 | #define __cmpxchg(ptr, old, new, size) \ | ||
311 | ({ \ | ||
312 | __typeof__(ptr) __ptr = (ptr); \ | ||
313 | __typeof__(*(ptr)) __old = (old); \ | ||
314 | __typeof__(*(ptr)) __new = (new); \ | ||
315 | __typeof__(*(ptr)) __ret; \ | ||
316 | register unsigned int __rc; \ | ||
317 | switch (size) { \ | ||
318 | case 4: \ | ||
319 | __asm__ __volatile__ ( \ | ||
320 | "0: lr.w %0, %2\n" \ | ||
321 | " bne %0, %z3, 1f\n" \ | ||
322 | " sc.w.rl %1, %z4, %2\n" \ | ||
323 | " bnez %1, 0b\n" \ | ||
324 | " fence rw, rw\n" \ | ||
325 | "1:\n" \ | ||
326 | : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ | ||
327 | : "rJ" (__old), "rJ" (__new) \ | ||
328 | : "memory"); \ | ||
329 | break; \ | ||
330 | case 8: \ | ||
331 | __asm__ __volatile__ ( \ | ||
332 | "0: lr.d %0, %2\n" \ | ||
333 | " bne %0, %z3, 1f\n" \ | ||
334 | " sc.d.rl %1, %z4, %2\n" \ | ||
335 | " bnez %1, 0b\n" \ | ||
336 | " fence rw, rw\n" \ | ||
337 | "1:\n" \ | ||
338 | : "=&r" (__ret), "=&r" (__rc), "+A" (*__ptr) \ | ||
339 | : "rJ" (__old), "rJ" (__new) \ | ||
340 | : "memory"); \ | ||
341 | break; \ | ||
342 | default: \ | ||
343 | BUILD_BUG(); \ | ||
344 | } \ | ||
345 | __ret; \ | ||
346 | }) | ||
109 | 347 | ||
110 | #define cmpxchg32(ptr, o, n) \ | 348 | #define cmpxchg(ptr, o, n) \ |
111 | ({ \ | 349 | ({ \ |
112 | BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ | 350 | __typeof__(*(ptr)) _o_ = (o); \ |
113 | cmpxchg((ptr), (o), (n)); \ | 351 | __typeof__(*(ptr)) _n_ = (n); \ |
352 | (__typeof__(*(ptr))) __cmpxchg((ptr), \ | ||
353 | _o_, _n_, sizeof(*(ptr))); \ | ||
114 | }) | 354 | }) |
115 | 355 | ||
116 | #define cmpxchg32_local(ptr, o, n) \ | 356 | #define cmpxchg_local(ptr, o, n) \ |
117 | ({ \ | 357 | (__cmpxchg_relaxed((ptr), (o), (n), sizeof(*(ptr)))) |
118 | BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ | 358 | |
119 | cmpxchg_local((ptr), (o), (n)); \ | 359 | #define cmpxchg32(ptr, o, n) \ |
360 | ({ \ | ||
361 | BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ | ||
362 | cmpxchg((ptr), (o), (n)); \ | ||
120 | }) | 363 | }) |
121 | 364 | ||
122 | #define cmpxchg64(ptr, o, n) \ | 365 | #define cmpxchg32_local(ptr, o, n) \ |
123 | ({ \ | 366 | ({ \ |
124 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | 367 | BUILD_BUG_ON(sizeof(*(ptr)) != 4); \ |
125 | cmpxchg((ptr), (o), (n)); \ | 368 | cmpxchg_relaxed((ptr), (o), (n)) \ |
126 | }) | 369 | }) |
127 | 370 | ||
128 | #define cmpxchg64_local(ptr, o, n) \ | 371 | #define cmpxchg64(ptr, o, n) \ |
129 | ({ \ | 372 | ({ \ |
130 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | 373 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ |
131 | cmpxchg_local((ptr), (o), (n)); \ | 374 | cmpxchg((ptr), (o), (n)); \ |
375 | }) | ||
376 | |||
377 | #define cmpxchg64_local(ptr, o, n) \ | ||
378 | ({ \ | ||
379 | BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ | ||
380 | cmpxchg_relaxed((ptr), (o), (n)); \ | ||
132 | }) | 381 | }) |
133 | 382 | ||
134 | #endif /* _ASM_RISCV_CMPXCHG_H */ | 383 | #endif /* _ASM_RISCV_CMPXCHG_H */ |
diff --git a/arch/riscv/include/asm/fence.h b/arch/riscv/include/asm/fence.h new file mode 100644 index 000000000000..2b443a3a487f --- /dev/null +++ b/arch/riscv/include/asm/fence.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef _ASM_RISCV_FENCE_H | ||
2 | #define _ASM_RISCV_FENCE_H | ||
3 | |||
4 | #ifdef CONFIG_SMP | ||
5 | #define RISCV_ACQUIRE_BARRIER "\tfence r , rw\n" | ||
6 | #define RISCV_RELEASE_BARRIER "\tfence rw, w\n" | ||
7 | #else | ||
8 | #define RISCV_ACQUIRE_BARRIER | ||
9 | #define RISCV_RELEASE_BARRIER | ||
10 | #endif | ||
11 | |||
12 | #endif /* _ASM_RISCV_FENCE_H */ | ||
diff --git a/arch/riscv/include/asm/ftrace.h b/arch/riscv/include/asm/ftrace.h index 66d4175eb13e..c6dcc5291f97 100644 --- a/arch/riscv/include/asm/ftrace.h +++ b/arch/riscv/include/asm/ftrace.h | |||
@@ -8,3 +8,59 @@ | |||
8 | #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER) | 8 | #if defined(CONFIG_FUNCTION_GRAPH_TRACER) && defined(CONFIG_FRAME_POINTER) |
9 | #define HAVE_FUNCTION_GRAPH_FP_TEST | 9 | #define HAVE_FUNCTION_GRAPH_FP_TEST |
10 | #endif | 10 | #endif |
11 | #define HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | ||
12 | |||
13 | #define ARCH_SUPPORTS_FTRACE_OPS 1 | ||
14 | #ifndef __ASSEMBLY__ | ||
15 | void _mcount(void); | ||
16 | static inline unsigned long ftrace_call_adjust(unsigned long addr) | ||
17 | { | ||
18 | return addr; | ||
19 | } | ||
20 | |||
21 | struct dyn_arch_ftrace { | ||
22 | }; | ||
23 | #endif | ||
24 | |||
25 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
26 | /* | ||
27 | * A general call in RISC-V is a pair of insts: | ||
28 | * 1) auipc: setting high-20 pc-related bits to ra register | ||
29 | * 2) jalr: setting low-12 offset to ra, jump to ra, and set ra to | ||
30 | * return address (original pc + 4) | ||
31 | * | ||
32 | * Dynamic ftrace generates probes to call sites, so we must deal with | ||
33 | * both auipc and jalr at the same time. | ||
34 | */ | ||
35 | |||
36 | #define MCOUNT_ADDR ((unsigned long)_mcount) | ||
37 | #define JALR_SIGN_MASK (0x00000800) | ||
38 | #define JALR_OFFSET_MASK (0x00000fff) | ||
39 | #define AUIPC_OFFSET_MASK (0xfffff000) | ||
40 | #define AUIPC_PAD (0x00001000) | ||
41 | #define JALR_SHIFT 20 | ||
42 | #define JALR_BASIC (0x000080e7) | ||
43 | #define AUIPC_BASIC (0x00000097) | ||
44 | #define NOP4 (0x00000013) | ||
45 | |||
46 | #define make_call(caller, callee, call) \ | ||
47 | do { \ | ||
48 | call[0] = to_auipc_insn((unsigned int)((unsigned long)callee - \ | ||
49 | (unsigned long)caller)); \ | ||
50 | call[1] = to_jalr_insn((unsigned int)((unsigned long)callee - \ | ||
51 | (unsigned long)caller)); \ | ||
52 | } while (0) | ||
53 | |||
54 | #define to_jalr_insn(offset) \ | ||
55 | (((offset & JALR_OFFSET_MASK) << JALR_SHIFT) | JALR_BASIC) | ||
56 | |||
57 | #define to_auipc_insn(offset) \ | ||
58 | ((offset & JALR_SIGN_MASK) ? \ | ||
59 | (((offset & AUIPC_OFFSET_MASK) + AUIPC_PAD) | AUIPC_BASIC) : \ | ||
60 | ((offset & AUIPC_OFFSET_MASK) | AUIPC_BASIC)) | ||
61 | |||
62 | /* | ||
63 | * Let auipc+jalr be the basic *mcount unit*, so we make it 8 bytes here. | ||
64 | */ | ||
65 | #define MCOUNT_INSN_SIZE 8 | ||
66 | #endif | ||
diff --git a/arch/riscv/include/asm/module.h b/arch/riscv/include/asm/module.h new file mode 100644 index 000000000000..349df33808c4 --- /dev/null +++ b/arch/riscv/include/asm/module.h | |||
@@ -0,0 +1,113 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* Copyright (C) 2017 Andes Technology Corporation */ | ||
3 | |||
4 | #ifndef _ASM_RISCV_MODULE_H | ||
5 | #define _ASM_RISCV_MODULE_H | ||
6 | |||
7 | #include <asm-generic/module.h> | ||
8 | |||
9 | #define MODULE_ARCH_VERMAGIC "riscv" | ||
10 | |||
11 | u64 module_emit_got_entry(struct module *mod, u64 val); | ||
12 | u64 module_emit_plt_entry(struct module *mod, u64 val); | ||
13 | |||
14 | #ifdef CONFIG_MODULE_SECTIONS | ||
15 | struct mod_section { | ||
16 | struct elf64_shdr *shdr; | ||
17 | int num_entries; | ||
18 | int max_entries; | ||
19 | }; | ||
20 | |||
21 | struct mod_arch_specific { | ||
22 | struct mod_section got; | ||
23 | struct mod_section plt; | ||
24 | struct mod_section got_plt; | ||
25 | }; | ||
26 | |||
27 | struct got_entry { | ||
28 | u64 symbol_addr; /* the real variable address */ | ||
29 | }; | ||
30 | |||
31 | static inline struct got_entry emit_got_entry(u64 val) | ||
32 | { | ||
33 | return (struct got_entry) {val}; | ||
34 | } | ||
35 | |||
36 | static inline struct got_entry *get_got_entry(u64 val, | ||
37 | const struct mod_section *sec) | ||
38 | { | ||
39 | struct got_entry *got = (struct got_entry *)sec->shdr->sh_addr; | ||
40 | int i; | ||
41 | for (i = 0; i < sec->num_entries; i++) { | ||
42 | if (got[i].symbol_addr == val) | ||
43 | return &got[i]; | ||
44 | } | ||
45 | return NULL; | ||
46 | } | ||
47 | |||
48 | struct plt_entry { | ||
49 | /* | ||
50 | * Trampoline code to real target address. The return address | ||
51 | * should be the original (pc+4) before entring plt entry. | ||
52 | */ | ||
53 | u32 insn_auipc; /* auipc t0, 0x0 */ | ||
54 | u32 insn_ld; /* ld t1, 0x10(t0) */ | ||
55 | u32 insn_jr; /* jr t1 */ | ||
56 | }; | ||
57 | |||
58 | #define OPC_AUIPC 0x0017 | ||
59 | #define OPC_LD 0x3003 | ||
60 | #define OPC_JALR 0x0067 | ||
61 | #define REG_T0 0x5 | ||
62 | #define REG_T1 0x6 | ||
63 | |||
64 | static inline struct plt_entry emit_plt_entry(u64 val, u64 plt, u64 got_plt) | ||
65 | { | ||
66 | /* | ||
67 | * U-Type encoding: | ||
68 | * +------------+----------+----------+ | ||
69 | * | imm[31:12] | rd[11:7] | opc[6:0] | | ||
70 | * +------------+----------+----------+ | ||
71 | * | ||
72 | * I-Type encoding: | ||
73 | * +------------+------------+--------+----------+----------+ | ||
74 | * | imm[31:20] | rs1[19:15] | funct3 | rd[11:7] | opc[6:0] | | ||
75 | * +------------+------------+--------+----------+----------+ | ||
76 | * | ||
77 | */ | ||
78 | u64 offset = got_plt - plt; | ||
79 | u32 hi20 = (offset + 0x800) & 0xfffff000; | ||
80 | u32 lo12 = (offset - hi20); | ||
81 | return (struct plt_entry) { | ||
82 | OPC_AUIPC | (REG_T0 << 7) | hi20, | ||
83 | OPC_LD | (lo12 << 20) | (REG_T0 << 15) | (REG_T1 << 7), | ||
84 | OPC_JALR | (REG_T1 << 15) | ||
85 | }; | ||
86 | } | ||
87 | |||
88 | static inline int get_got_plt_idx(u64 val, const struct mod_section *sec) | ||
89 | { | ||
90 | struct got_entry *got_plt = (struct got_entry *)sec->shdr->sh_addr; | ||
91 | int i; | ||
92 | for (i = 0; i < sec->num_entries; i++) { | ||
93 | if (got_plt[i].symbol_addr == val) | ||
94 | return i; | ||
95 | } | ||
96 | return -1; | ||
97 | } | ||
98 | |||
99 | static inline struct plt_entry *get_plt_entry(u64 val, | ||
100 | const struct mod_section *sec_plt, | ||
101 | const struct mod_section *sec_got_plt) | ||
102 | { | ||
103 | struct plt_entry *plt = (struct plt_entry *)sec_plt->shdr->sh_addr; | ||
104 | int got_plt_idx = get_got_plt_idx(val, sec_got_plt); | ||
105 | if (got_plt_idx >= 0) | ||
106 | return plt + got_plt_idx; | ||
107 | else | ||
108 | return NULL; | ||
109 | } | ||
110 | |||
111 | #endif /* CONFIG_MODULE_SECTIONS */ | ||
112 | |||
113 | #endif /* _ASM_RISCV_MODULE_H */ | ||
diff --git a/arch/riscv/include/asm/spinlock.h b/arch/riscv/include/asm/spinlock.h index 2fd27e8ef1fd..8eb26d1ede81 100644 --- a/arch/riscv/include/asm/spinlock.h +++ b/arch/riscv/include/asm/spinlock.h | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <asm/current.h> | 19 | #include <asm/current.h> |
20 | #include <asm/fence.h> | ||
20 | 21 | ||
21 | /* | 22 | /* |
22 | * Simple spin lock operations. These provide no fairness guarantees. | 23 | * Simple spin lock operations. These provide no fairness guarantees. |
@@ -28,10 +29,7 @@ | |||
28 | 29 | ||
29 | static inline void arch_spin_unlock(arch_spinlock_t *lock) | 30 | static inline void arch_spin_unlock(arch_spinlock_t *lock) |
30 | { | 31 | { |
31 | __asm__ __volatile__ ( | 32 | smp_store_release(&lock->lock, 0); |
32 | "amoswap.w.rl x0, x0, %0" | ||
33 | : "=A" (lock->lock) | ||
34 | :: "memory"); | ||
35 | } | 33 | } |
36 | 34 | ||
37 | static inline int arch_spin_trylock(arch_spinlock_t *lock) | 35 | static inline int arch_spin_trylock(arch_spinlock_t *lock) |
@@ -39,7 +37,8 @@ static inline int arch_spin_trylock(arch_spinlock_t *lock) | |||
39 | int tmp = 1, busy; | 37 | int tmp = 1, busy; |
40 | 38 | ||
41 | __asm__ __volatile__ ( | 39 | __asm__ __volatile__ ( |
42 | "amoswap.w.aq %0, %2, %1" | 40 | " amoswap.w %0, %2, %1\n" |
41 | RISCV_ACQUIRE_BARRIER | ||
43 | : "=r" (busy), "+A" (lock->lock) | 42 | : "=r" (busy), "+A" (lock->lock) |
44 | : "r" (tmp) | 43 | : "r" (tmp) |
45 | : "memory"); | 44 | : "memory"); |
@@ -68,8 +67,9 @@ static inline void arch_read_lock(arch_rwlock_t *lock) | |||
68 | "1: lr.w %1, %0\n" | 67 | "1: lr.w %1, %0\n" |
69 | " bltz %1, 1b\n" | 68 | " bltz %1, 1b\n" |
70 | " addi %1, %1, 1\n" | 69 | " addi %1, %1, 1\n" |
71 | " sc.w.aq %1, %1, %0\n" | 70 | " sc.w %1, %1, %0\n" |
72 | " bnez %1, 1b\n" | 71 | " bnez %1, 1b\n" |
72 | RISCV_ACQUIRE_BARRIER | ||
73 | : "+A" (lock->lock), "=&r" (tmp) | 73 | : "+A" (lock->lock), "=&r" (tmp) |
74 | :: "memory"); | 74 | :: "memory"); |
75 | } | 75 | } |
@@ -82,8 +82,9 @@ static inline void arch_write_lock(arch_rwlock_t *lock) | |||
82 | "1: lr.w %1, %0\n" | 82 | "1: lr.w %1, %0\n" |
83 | " bnez %1, 1b\n" | 83 | " bnez %1, 1b\n" |
84 | " li %1, -1\n" | 84 | " li %1, -1\n" |
85 | " sc.w.aq %1, %1, %0\n" | 85 | " sc.w %1, %1, %0\n" |
86 | " bnez %1, 1b\n" | 86 | " bnez %1, 1b\n" |
87 | RISCV_ACQUIRE_BARRIER | ||
87 | : "+A" (lock->lock), "=&r" (tmp) | 88 | : "+A" (lock->lock), "=&r" (tmp) |
88 | :: "memory"); | 89 | :: "memory"); |
89 | } | 90 | } |
@@ -96,8 +97,9 @@ static inline int arch_read_trylock(arch_rwlock_t *lock) | |||
96 | "1: lr.w %1, %0\n" | 97 | "1: lr.w %1, %0\n" |
97 | " bltz %1, 1f\n" | 98 | " bltz %1, 1f\n" |
98 | " addi %1, %1, 1\n" | 99 | " addi %1, %1, 1\n" |
99 | " sc.w.aq %1, %1, %0\n" | 100 | " sc.w %1, %1, %0\n" |
100 | " bnez %1, 1b\n" | 101 | " bnez %1, 1b\n" |
102 | RISCV_ACQUIRE_BARRIER | ||
101 | "1:\n" | 103 | "1:\n" |
102 | : "+A" (lock->lock), "=&r" (busy) | 104 | : "+A" (lock->lock), "=&r" (busy) |
103 | :: "memory"); | 105 | :: "memory"); |
@@ -113,8 +115,9 @@ static inline int arch_write_trylock(arch_rwlock_t *lock) | |||
113 | "1: lr.w %1, %0\n" | 115 | "1: lr.w %1, %0\n" |
114 | " bnez %1, 1f\n" | 116 | " bnez %1, 1f\n" |
115 | " li %1, -1\n" | 117 | " li %1, -1\n" |
116 | " sc.w.aq %1, %1, %0\n" | 118 | " sc.w %1, %1, %0\n" |
117 | " bnez %1, 1b\n" | 119 | " bnez %1, 1b\n" |
120 | RISCV_ACQUIRE_BARRIER | ||
118 | "1:\n" | 121 | "1:\n" |
119 | : "+A" (lock->lock), "=&r" (busy) | 122 | : "+A" (lock->lock), "=&r" (busy) |
120 | :: "memory"); | 123 | :: "memory"); |
@@ -125,7 +128,8 @@ static inline int arch_write_trylock(arch_rwlock_t *lock) | |||
125 | static inline void arch_read_unlock(arch_rwlock_t *lock) | 128 | static inline void arch_read_unlock(arch_rwlock_t *lock) |
126 | { | 129 | { |
127 | __asm__ __volatile__( | 130 | __asm__ __volatile__( |
128 | "amoadd.w.rl x0, %1, %0" | 131 | RISCV_RELEASE_BARRIER |
132 | " amoadd.w x0, %1, %0\n" | ||
129 | : "+A" (lock->lock) | 133 | : "+A" (lock->lock) |
130 | : "r" (-1) | 134 | : "r" (-1) |
131 | : "memory"); | 135 | : "memory"); |
@@ -133,10 +137,7 @@ static inline void arch_read_unlock(arch_rwlock_t *lock) | |||
133 | 137 | ||
134 | static inline void arch_write_unlock(arch_rwlock_t *lock) | 138 | static inline void arch_write_unlock(arch_rwlock_t *lock) |
135 | { | 139 | { |
136 | __asm__ __volatile__ ( | 140 | smp_store_release(&lock->lock, 0); |
137 | "amoswap.w.rl x0, x0, %0" | ||
138 | : "=A" (lock->lock) | ||
139 | :: "memory"); | ||
140 | } | 141 | } |
141 | 142 | ||
142 | #endif /* _ASM_RISCV_SPINLOCK_H */ | 143 | #endif /* _ASM_RISCV_SPINLOCK_H */ |
diff --git a/arch/riscv/include/uapi/asm/elf.h b/arch/riscv/include/uapi/asm/elf.h index a510edfa8226..5cae4c30cd8e 100644 --- a/arch/riscv/include/uapi/asm/elf.h +++ b/arch/riscv/include/uapi/asm/elf.h | |||
@@ -79,5 +79,12 @@ typedef union __riscv_fp_state elf_fpregset_t; | |||
79 | #define R_RISCV_TPREL_I 49 | 79 | #define R_RISCV_TPREL_I 49 |
80 | #define R_RISCV_TPREL_S 50 | 80 | #define R_RISCV_TPREL_S 50 |
81 | #define R_RISCV_RELAX 51 | 81 | #define R_RISCV_RELAX 51 |
82 | #define R_RISCV_SUB6 52 | ||
83 | #define R_RISCV_SET6 53 | ||
84 | #define R_RISCV_SET8 54 | ||
85 | #define R_RISCV_SET16 55 | ||
86 | #define R_RISCV_SET32 56 | ||
87 | #define R_RISCV_32_PCREL 57 | ||
88 | |||
82 | 89 | ||
83 | #endif /* _UAPI_ASM_ELF_H */ | 90 | #endif /* _UAPI_ASM_ELF_H */ |
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile index 196f62ffc428..8586dd96c2f0 100644 --- a/arch/riscv/kernel/Makefile +++ b/arch/riscv/kernel/Makefile | |||
@@ -34,7 +34,9 @@ CFLAGS_setup.o := -mcmodel=medany | |||
34 | obj-$(CONFIG_SMP) += smpboot.o | 34 | obj-$(CONFIG_SMP) += smpboot.o |
35 | obj-$(CONFIG_SMP) += smp.o | 35 | obj-$(CONFIG_SMP) += smp.o |
36 | obj-$(CONFIG_MODULES) += module.o | 36 | obj-$(CONFIG_MODULES) += module.o |
37 | obj-$(CONFIG_FUNCTION_TRACER) += mcount.o | 37 | obj-$(CONFIG_MODULE_SECTIONS) += module-sections.o |
38 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 38 | |
39 | obj-$(CONFIG_FUNCTION_TRACER) += mcount.o ftrace.o | ||
40 | obj-$(CONFIG_DYNAMIC_FTRACE) += mcount-dyn.o | ||
39 | 41 | ||
40 | clean: | 42 | clean: |
diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c index d0de68d144cb..1157b6b52d25 100644 --- a/arch/riscv/kernel/ftrace.c +++ b/arch/riscv/kernel/ftrace.c | |||
@@ -6,9 +6,126 @@ | |||
6 | */ | 6 | */ |
7 | 7 | ||
8 | #include <linux/ftrace.h> | 8 | #include <linux/ftrace.h> |
9 | #include <linux/uaccess.h> | ||
10 | #include <asm/cacheflush.h> | ||
9 | 11 | ||
12 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
13 | static int ftrace_check_current_call(unsigned long hook_pos, | ||
14 | unsigned int *expected) | ||
15 | { | ||
16 | unsigned int replaced[2]; | ||
17 | unsigned int nops[2] = {NOP4, NOP4}; | ||
18 | |||
19 | /* we expect nops at the hook position */ | ||
20 | if (!expected) | ||
21 | expected = nops; | ||
22 | |||
23 | /* | ||
24 | * Read the text we want to modify; | ||
25 | * return must be -EFAULT on read error | ||
26 | */ | ||
27 | if (probe_kernel_read(replaced, (void *)hook_pos, MCOUNT_INSN_SIZE)) | ||
28 | return -EFAULT; | ||
29 | |||
30 | /* | ||
31 | * Make sure it is what we expect it to be; | ||
32 | * return must be -EINVAL on failed comparison | ||
33 | */ | ||
34 | if (memcmp(expected, replaced, sizeof(replaced))) { | ||
35 | pr_err("%p: expected (%08x %08x) but get (%08x %08x)", | ||
36 | (void *)hook_pos, expected[0], expected[1], replaced[0], | ||
37 | replaced[1]); | ||
38 | return -EINVAL; | ||
39 | } | ||
40 | |||
41 | return 0; | ||
42 | } | ||
43 | |||
44 | static int __ftrace_modify_call(unsigned long hook_pos, unsigned long target, | ||
45 | bool enable) | ||
46 | { | ||
47 | unsigned int call[2]; | ||
48 | unsigned int nops[2] = {NOP4, NOP4}; | ||
49 | int ret = 0; | ||
50 | |||
51 | make_call(hook_pos, target, call); | ||
52 | |||
53 | /* replace the auipc-jalr pair at once */ | ||
54 | ret = probe_kernel_write((void *)hook_pos, enable ? call : nops, | ||
55 | MCOUNT_INSN_SIZE); | ||
56 | /* return must be -EPERM on write error */ | ||
57 | if (ret) | ||
58 | return -EPERM; | ||
59 | |||
60 | smp_mb(); | ||
61 | flush_icache_range((void *)hook_pos, (void *)hook_pos + MCOUNT_INSN_SIZE); | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr) | ||
67 | { | ||
68 | int ret = ftrace_check_current_call(rec->ip, NULL); | ||
69 | |||
70 | if (ret) | ||
71 | return ret; | ||
72 | |||
73 | return __ftrace_modify_call(rec->ip, addr, true); | ||
74 | } | ||
75 | |||
76 | int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec, | ||
77 | unsigned long addr) | ||
78 | { | ||
79 | unsigned int call[2]; | ||
80 | int ret; | ||
81 | |||
82 | make_call(rec->ip, addr, call); | ||
83 | ret = ftrace_check_current_call(rec->ip, call); | ||
84 | |||
85 | if (ret) | ||
86 | return ret; | ||
87 | |||
88 | return __ftrace_modify_call(rec->ip, addr, false); | ||
89 | } | ||
90 | |||
91 | int ftrace_update_ftrace_func(ftrace_func_t func) | ||
92 | { | ||
93 | int ret = __ftrace_modify_call((unsigned long)&ftrace_call, | ||
94 | (unsigned long)func, true); | ||
95 | if (!ret) { | ||
96 | ret = __ftrace_modify_call((unsigned long)&ftrace_regs_call, | ||
97 | (unsigned long)func, true); | ||
98 | } | ||
99 | |||
100 | return ret; | ||
101 | } | ||
102 | |||
103 | int __init ftrace_dyn_arch_init(void) | ||
104 | { | ||
105 | return 0; | ||
106 | } | ||
107 | #endif | ||
108 | |||
109 | #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS | ||
110 | int ftrace_modify_call(struct dyn_ftrace *rec, unsigned long old_addr, | ||
111 | unsigned long addr) | ||
112 | { | ||
113 | unsigned int call[2]; | ||
114 | int ret; | ||
115 | |||
116 | make_call(rec->ip, old_addr, call); | ||
117 | ret = ftrace_check_current_call(rec->ip, call); | ||
118 | |||
119 | if (ret) | ||
120 | return ret; | ||
121 | |||
122 | return __ftrace_modify_call(rec->ip, addr, true); | ||
123 | } | ||
124 | #endif | ||
125 | |||
126 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
10 | /* | 127 | /* |
11 | * Most of this file is copied from arm64. | 128 | * Most of this function is copied from arm64. |
12 | */ | 129 | */ |
13 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | 130 | void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, |
14 | unsigned long frame_pointer) | 131 | unsigned long frame_pointer) |
@@ -34,8 +151,62 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr, | |||
34 | return; | 151 | return; |
35 | 152 | ||
36 | err = ftrace_push_return_trace(old, self_addr, &trace.depth, | 153 | err = ftrace_push_return_trace(old, self_addr, &trace.depth, |
37 | frame_pointer, NULL); | 154 | frame_pointer, parent); |
38 | if (err == -EBUSY) | 155 | if (err == -EBUSY) |
39 | return; | 156 | return; |
40 | *parent = return_hooker; | 157 | *parent = return_hooker; |
41 | } | 158 | } |
159 | |||
160 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
161 | extern void ftrace_graph_call(void); | ||
162 | int ftrace_enable_ftrace_graph_caller(void) | ||
163 | { | ||
164 | unsigned int call[2]; | ||
165 | static int init_graph = 1; | ||
166 | int ret; | ||
167 | |||
168 | make_call(&ftrace_graph_call, &ftrace_stub, call); | ||
169 | |||
170 | /* | ||
171 | * When enabling graph tracer for the first time, ftrace_graph_call | ||
172 | * should contains a call to ftrace_stub. Once it has been disabled, | ||
173 | * the 8-bytes at the position becomes NOPs. | ||
174 | */ | ||
175 | if (init_graph) { | ||
176 | ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call, | ||
177 | call); | ||
178 | init_graph = 0; | ||
179 | } else { | ||
180 | ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call, | ||
181 | NULL); | ||
182 | } | ||
183 | |||
184 | if (ret) | ||
185 | return ret; | ||
186 | |||
187 | return __ftrace_modify_call((unsigned long)&ftrace_graph_call, | ||
188 | (unsigned long)&prepare_ftrace_return, true); | ||
189 | } | ||
190 | |||
191 | int ftrace_disable_ftrace_graph_caller(void) | ||
192 | { | ||
193 | unsigned int call[2]; | ||
194 | int ret; | ||
195 | |||
196 | make_call(&ftrace_graph_call, &prepare_ftrace_return, call); | ||
197 | |||
198 | /* | ||
199 | * This is to make sure that ftrace_enable_ftrace_graph_caller | ||
200 | * did the right thing. | ||
201 | */ | ||
202 | ret = ftrace_check_current_call((unsigned long)&ftrace_graph_call, | ||
203 | call); | ||
204 | |||
205 | if (ret) | ||
206 | return ret; | ||
207 | |||
208 | return __ftrace_modify_call((unsigned long)&ftrace_graph_call, | ||
209 | (unsigned long)&prepare_ftrace_return, false); | ||
210 | } | ||
211 | #endif /* CONFIG_DYNAMIC_FTRACE */ | ||
212 | #endif /* CONFIG_FUNCTION_GRAPH_TRACER */ | ||
diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S new file mode 100644 index 000000000000..35a6ed76cb8b --- /dev/null +++ b/arch/riscv/kernel/mcount-dyn.S | |||
@@ -0,0 +1,239 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* Copyright (C) 2017 Andes Technology Corporation */ | ||
3 | |||
4 | #include <linux/init.h> | ||
5 | #include <linux/linkage.h> | ||
6 | #include <asm/asm.h> | ||
7 | #include <asm/csr.h> | ||
8 | #include <asm/unistd.h> | ||
9 | #include <asm/thread_info.h> | ||
10 | #include <asm/asm-offsets.h> | ||
11 | #include <asm-generic/export.h> | ||
12 | #include <asm/ftrace.h> | ||
13 | |||
14 | .text | ||
15 | |||
16 | .macro SAVE_ABI_STATE | ||
17 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
18 | addi sp, sp, -48 | ||
19 | sd s0, 32(sp) | ||
20 | sd ra, 40(sp) | ||
21 | addi s0, sp, 48 | ||
22 | sd t0, 24(sp) | ||
23 | sd t1, 16(sp) | ||
24 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | ||
25 | sd t2, 8(sp) | ||
26 | #endif | ||
27 | #else | ||
28 | addi sp, sp, -16 | ||
29 | sd s0, 0(sp) | ||
30 | sd ra, 8(sp) | ||
31 | addi s0, sp, 16 | ||
32 | #endif | ||
33 | .endm | ||
34 | |||
35 | .macro RESTORE_ABI_STATE | ||
36 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
37 | ld s0, 32(sp) | ||
38 | ld ra, 40(sp) | ||
39 | addi sp, sp, 48 | ||
40 | #else | ||
41 | ld ra, 8(sp) | ||
42 | ld s0, 0(sp) | ||
43 | addi sp, sp, 16 | ||
44 | #endif | ||
45 | .endm | ||
46 | |||
47 | .macro RESTORE_GRAPH_ARGS | ||
48 | ld a0, 24(sp) | ||
49 | ld a1, 16(sp) | ||
50 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | ||
51 | ld a2, 8(sp) | ||
52 | #endif | ||
53 | .endm | ||
54 | |||
55 | ENTRY(ftrace_graph_caller) | ||
56 | addi sp, sp, -16 | ||
57 | sd s0, 0(sp) | ||
58 | sd ra, 8(sp) | ||
59 | addi s0, sp, 16 | ||
60 | ftrace_graph_call: | ||
61 | .global ftrace_graph_call | ||
62 | /* | ||
63 | * Calling ftrace_enable/disable_ftrace_graph_caller would overwrite the | ||
64 | * call below. Check ftrace_modify_all_code for details. | ||
65 | */ | ||
66 | call ftrace_stub | ||
67 | ld ra, 8(sp) | ||
68 | ld s0, 0(sp) | ||
69 | addi sp, sp, 16 | ||
70 | ret | ||
71 | ENDPROC(ftrace_graph_caller) | ||
72 | |||
73 | ENTRY(ftrace_caller) | ||
74 | /* | ||
75 | * a0: the address in the caller when calling ftrace_caller | ||
76 | * a1: the caller's return address | ||
77 | * a2: the address of global variable function_trace_op | ||
78 | */ | ||
79 | ld a1, -8(s0) | ||
80 | addi a0, ra, -MCOUNT_INSN_SIZE | ||
81 | la t5, function_trace_op | ||
82 | ld a2, 0(t5) | ||
83 | |||
84 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
85 | /* | ||
86 | * the graph tracer (specifically, prepare_ftrace_return) needs these | ||
87 | * arguments but for now the function tracer occupies the regs, so we | ||
88 | * save them in temporary regs to recover later. | ||
89 | */ | ||
90 | addi t0, s0, -8 | ||
91 | mv t1, a0 | ||
92 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | ||
93 | ld t2, -16(s0) | ||
94 | #endif | ||
95 | #endif | ||
96 | |||
97 | SAVE_ABI_STATE | ||
98 | ftrace_call: | ||
99 | .global ftrace_call | ||
100 | /* | ||
101 | * For the dynamic ftrace to work, here we should reserve at least | ||
102 | * 8 bytes for a functional auipc-jalr pair. The following call | ||
103 | * serves this purpose. | ||
104 | * | ||
105 | * Calling ftrace_update_ftrace_func would overwrite the nops below. | ||
106 | * Check ftrace_modify_all_code for details. | ||
107 | */ | ||
108 | call ftrace_stub | ||
109 | |||
110 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
111 | RESTORE_GRAPH_ARGS | ||
112 | call ftrace_graph_caller | ||
113 | #endif | ||
114 | |||
115 | RESTORE_ABI_STATE | ||
116 | ret | ||
117 | ENDPROC(ftrace_caller) | ||
118 | |||
119 | #ifdef CONFIG_DYNAMIC_FTRACE_WITH_REGS | ||
120 | .macro SAVE_ALL | ||
121 | addi sp, sp, -(PT_SIZE_ON_STACK+16) | ||
122 | sd s0, (PT_SIZE_ON_STACK)(sp) | ||
123 | sd ra, (PT_SIZE_ON_STACK+8)(sp) | ||
124 | addi s0, sp, (PT_SIZE_ON_STACK+16) | ||
125 | |||
126 | sd x1, PT_RA(sp) | ||
127 | sd x2, PT_SP(sp) | ||
128 | sd x3, PT_GP(sp) | ||
129 | sd x4, PT_TP(sp) | ||
130 | sd x5, PT_T0(sp) | ||
131 | sd x6, PT_T1(sp) | ||
132 | sd x7, PT_T2(sp) | ||
133 | sd x8, PT_S0(sp) | ||
134 | sd x9, PT_S1(sp) | ||
135 | sd x10, PT_A0(sp) | ||
136 | sd x11, PT_A1(sp) | ||
137 | sd x12, PT_A2(sp) | ||
138 | sd x13, PT_A3(sp) | ||
139 | sd x14, PT_A4(sp) | ||
140 | sd x15, PT_A5(sp) | ||
141 | sd x16, PT_A6(sp) | ||
142 | sd x17, PT_A7(sp) | ||
143 | sd x18, PT_S2(sp) | ||
144 | sd x19, PT_S3(sp) | ||
145 | sd x20, PT_S4(sp) | ||
146 | sd x21, PT_S5(sp) | ||
147 | sd x22, PT_S6(sp) | ||
148 | sd x23, PT_S7(sp) | ||
149 | sd x24, PT_S8(sp) | ||
150 | sd x25, PT_S9(sp) | ||
151 | sd x26, PT_S10(sp) | ||
152 | sd x27, PT_S11(sp) | ||
153 | sd x28, PT_T3(sp) | ||
154 | sd x29, PT_T4(sp) | ||
155 | sd x30, PT_T5(sp) | ||
156 | sd x31, PT_T6(sp) | ||
157 | .endm | ||
158 | |||
159 | .macro RESTORE_ALL | ||
160 | ld x1, PT_RA(sp) | ||
161 | ld x2, PT_SP(sp) | ||
162 | ld x3, PT_GP(sp) | ||
163 | ld x4, PT_TP(sp) | ||
164 | ld x5, PT_T0(sp) | ||
165 | ld x6, PT_T1(sp) | ||
166 | ld x7, PT_T2(sp) | ||
167 | ld x8, PT_S0(sp) | ||
168 | ld x9, PT_S1(sp) | ||
169 | ld x10, PT_A0(sp) | ||
170 | ld x11, PT_A1(sp) | ||
171 | ld x12, PT_A2(sp) | ||
172 | ld x13, PT_A3(sp) | ||
173 | ld x14, PT_A4(sp) | ||
174 | ld x15, PT_A5(sp) | ||
175 | ld x16, PT_A6(sp) | ||
176 | ld x17, PT_A7(sp) | ||
177 | ld x18, PT_S2(sp) | ||
178 | ld x19, PT_S3(sp) | ||
179 | ld x20, PT_S4(sp) | ||
180 | ld x21, PT_S5(sp) | ||
181 | ld x22, PT_S6(sp) | ||
182 | ld x23, PT_S7(sp) | ||
183 | ld x24, PT_S8(sp) | ||
184 | ld x25, PT_S9(sp) | ||
185 | ld x26, PT_S10(sp) | ||
186 | ld x27, PT_S11(sp) | ||
187 | ld x28, PT_T3(sp) | ||
188 | ld x29, PT_T4(sp) | ||
189 | ld x30, PT_T5(sp) | ||
190 | ld x31, PT_T6(sp) | ||
191 | |||
192 | ld s0, (PT_SIZE_ON_STACK)(sp) | ||
193 | ld ra, (PT_SIZE_ON_STACK+8)(sp) | ||
194 | addi sp, sp, (PT_SIZE_ON_STACK+16) | ||
195 | .endm | ||
196 | |||
197 | .macro RESTORE_GRAPH_REG_ARGS | ||
198 | ld a0, PT_T0(sp) | ||
199 | ld a1, PT_T1(sp) | ||
200 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | ||
201 | ld a2, PT_T2(sp) | ||
202 | #endif | ||
203 | .endm | ||
204 | |||
205 | /* | ||
206 | * Most of the contents are the same as ftrace_caller. | ||
207 | */ | ||
208 | ENTRY(ftrace_regs_caller) | ||
209 | /* | ||
210 | * a3: the address of all registers in the stack | ||
211 | */ | ||
212 | ld a1, -8(s0) | ||
213 | addi a0, ra, -MCOUNT_INSN_SIZE | ||
214 | la t5, function_trace_op | ||
215 | ld a2, 0(t5) | ||
216 | addi a3, sp, -(PT_SIZE_ON_STACK+16) | ||
217 | |||
218 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
219 | addi t0, s0, -8 | ||
220 | mv t1, a0 | ||
221 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | ||
222 | ld t2, -16(s0) | ||
223 | #endif | ||
224 | #endif | ||
225 | SAVE_ALL | ||
226 | |||
227 | ftrace_regs_call: | ||
228 | .global ftrace_regs_call | ||
229 | call ftrace_stub | ||
230 | |||
231 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | ||
232 | RESTORE_GRAPH_REG_ARGS | ||
233 | call ftrace_graph_caller | ||
234 | #endif | ||
235 | |||
236 | RESTORE_ALL | ||
237 | ret | ||
238 | ENDPROC(ftrace_regs_caller) | ||
239 | #endif /* CONFIG_DYNAMIC_FTRACE_WITH_REGS */ | ||
diff --git a/arch/riscv/kernel/mcount.S b/arch/riscv/kernel/mcount.S index c46a778627be..ce9bdc57a2a1 100644 --- a/arch/riscv/kernel/mcount.S +++ b/arch/riscv/kernel/mcount.S | |||
@@ -32,13 +32,13 @@ | |||
32 | addi s0, sp, 32 | 32 | addi s0, sp, 32 |
33 | .endm | 33 | .endm |
34 | 34 | ||
35 | .macro STORE_ABI_STATE | 35 | .macro RESTORE_ABI_STATE |
36 | ld ra, 8(sp) | 36 | ld ra, 8(sp) |
37 | ld s0, 0(sp) | 37 | ld s0, 0(sp) |
38 | addi sp, sp, 16 | 38 | addi sp, sp, 16 |
39 | .endm | 39 | .endm |
40 | 40 | ||
41 | .macro STORE_RET_ABI_STATE | 41 | .macro RESTORE_RET_ABI_STATE |
42 | ld ra, 24(sp) | 42 | ld ra, 24(sp) |
43 | ld s0, 16(sp) | 43 | ld s0, 16(sp) |
44 | ld a0, 8(sp) | 44 | ld a0, 8(sp) |
@@ -46,6 +46,10 @@ | |||
46 | .endm | 46 | .endm |
47 | 47 | ||
48 | ENTRY(ftrace_stub) | 48 | ENTRY(ftrace_stub) |
49 | #ifdef CONFIG_DYNAMIC_FTRACE | ||
50 | .global _mcount | ||
51 | .set _mcount, ftrace_stub | ||
52 | #endif | ||
49 | ret | 53 | ret |
50 | ENDPROC(ftrace_stub) | 54 | ENDPROC(ftrace_stub) |
51 | 55 | ||
@@ -66,15 +70,15 @@ ENTRY(return_to_handler) | |||
66 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST | 70 | #ifdef HAVE_FUNCTION_GRAPH_FP_TEST |
67 | mv a0, t6 | 71 | mv a0, t6 |
68 | #endif | 72 | #endif |
69 | la t0, ftrace_return_to_handler | 73 | call ftrace_return_to_handler |
70 | jalr t0 | ||
71 | mv a1, a0 | 74 | mv a1, a0 |
72 | STORE_RET_ABI_STATE | 75 | RESTORE_RET_ABI_STATE |
73 | jalr a1 | 76 | jalr a1 |
74 | ENDPROC(return_to_handler) | 77 | ENDPROC(return_to_handler) |
75 | EXPORT_SYMBOL(return_to_handler) | 78 | EXPORT_SYMBOL(return_to_handler) |
76 | #endif | 79 | #endif |
77 | 80 | ||
81 | #ifndef CONFIG_DYNAMIC_FTRACE | ||
78 | ENTRY(_mcount) | 82 | ENTRY(_mcount) |
79 | la t4, ftrace_stub | 83 | la t4, ftrace_stub |
80 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 84 | #ifdef CONFIG_FUNCTION_GRAPH_TRACER |
@@ -104,9 +108,8 @@ do_ftrace_graph_caller: | |||
104 | ld a2, -16(s0) | 108 | ld a2, -16(s0) |
105 | #endif | 109 | #endif |
106 | SAVE_ABI_STATE | 110 | SAVE_ABI_STATE |
107 | la t0, prepare_ftrace_return | 111 | call prepare_ftrace_return |
108 | jalr t0 | 112 | RESTORE_ABI_STATE |
109 | STORE_ABI_STATE | ||
110 | ret | 113 | ret |
111 | #endif | 114 | #endif |
112 | 115 | ||
@@ -120,7 +123,8 @@ do_trace: | |||
120 | 123 | ||
121 | SAVE_ABI_STATE | 124 | SAVE_ABI_STATE |
122 | jalr t5 | 125 | jalr t5 |
123 | STORE_ABI_STATE | 126 | RESTORE_ABI_STATE |
124 | ret | 127 | ret |
125 | ENDPROC(_mcount) | 128 | ENDPROC(_mcount) |
126 | EXPORT_SYMBOL(_mcount) | 129 | EXPORT_SYMBOL(_mcount) |
130 | #endif | ||
diff --git a/arch/riscv/kernel/module-sections.c b/arch/riscv/kernel/module-sections.c new file mode 100644 index 000000000000..bbbd26e19bfd --- /dev/null +++ b/arch/riscv/kernel/module-sections.c | |||
@@ -0,0 +1,156 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 | ||
2 | * | ||
3 | * Copyright (C) 2014-2017 Linaro Ltd. <ard.biesheuvel@linaro.org> | ||
4 | * | ||
5 | * Copyright (C) 2018 Andes Technology Corporation <zong@andestech.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/elf.h> | ||
9 | #include <linux/kernel.h> | ||
10 | #include <linux/module.h> | ||
11 | |||
12 | u64 module_emit_got_entry(struct module *mod, u64 val) | ||
13 | { | ||
14 | struct mod_section *got_sec = &mod->arch.got; | ||
15 | int i = got_sec->num_entries; | ||
16 | struct got_entry *got = get_got_entry(val, got_sec); | ||
17 | |||
18 | if (got) | ||
19 | return (u64)got; | ||
20 | |||
21 | /* There is no duplicate entry, create a new one */ | ||
22 | got = (struct got_entry *)got_sec->shdr->sh_addr; | ||
23 | got[i] = emit_got_entry(val); | ||
24 | |||
25 | got_sec->num_entries++; | ||
26 | BUG_ON(got_sec->num_entries > got_sec->max_entries); | ||
27 | |||
28 | return (u64)&got[i]; | ||
29 | } | ||
30 | |||
31 | u64 module_emit_plt_entry(struct module *mod, u64 val) | ||
32 | { | ||
33 | struct mod_section *got_plt_sec = &mod->arch.got_plt; | ||
34 | struct got_entry *got_plt; | ||
35 | struct mod_section *plt_sec = &mod->arch.plt; | ||
36 | struct plt_entry *plt = get_plt_entry(val, plt_sec, got_plt_sec); | ||
37 | int i = plt_sec->num_entries; | ||
38 | |||
39 | if (plt) | ||
40 | return (u64)plt; | ||
41 | |||
42 | /* There is no duplicate entry, create a new one */ | ||
43 | got_plt = (struct got_entry *)got_plt_sec->shdr->sh_addr; | ||
44 | got_plt[i] = emit_got_entry(val); | ||
45 | plt = (struct plt_entry *)plt_sec->shdr->sh_addr; | ||
46 | plt[i] = emit_plt_entry(val, (u64)&plt[i], (u64)&got_plt[i]); | ||
47 | |||
48 | plt_sec->num_entries++; | ||
49 | got_plt_sec->num_entries++; | ||
50 | BUG_ON(plt_sec->num_entries > plt_sec->max_entries); | ||
51 | |||
52 | return (u64)&plt[i]; | ||
53 | } | ||
54 | |||
55 | static int is_rela_equal(const Elf64_Rela *x, const Elf64_Rela *y) | ||
56 | { | ||
57 | return x->r_info == y->r_info && x->r_addend == y->r_addend; | ||
58 | } | ||
59 | |||
60 | static bool duplicate_rela(const Elf64_Rela *rela, int idx) | ||
61 | { | ||
62 | int i; | ||
63 | for (i = 0; i < idx; i++) { | ||
64 | if (is_rela_equal(&rela[i], &rela[idx])) | ||
65 | return true; | ||
66 | } | ||
67 | return false; | ||
68 | } | ||
69 | |||
70 | static void count_max_entries(Elf64_Rela *relas, int num, | ||
71 | unsigned int *plts, unsigned int *gots) | ||
72 | { | ||
73 | unsigned int type, i; | ||
74 | |||
75 | for (i = 0; i < num; i++) { | ||
76 | type = ELF64_R_TYPE(relas[i].r_info); | ||
77 | if (type == R_RISCV_CALL_PLT) { | ||
78 | if (!duplicate_rela(relas, i)) | ||
79 | (*plts)++; | ||
80 | } else if (type == R_RISCV_GOT_HI20) { | ||
81 | if (!duplicate_rela(relas, i)) | ||
82 | (*gots)++; | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | |||
87 | int module_frob_arch_sections(Elf_Ehdr *ehdr, Elf_Shdr *sechdrs, | ||
88 | char *secstrings, struct module *mod) | ||
89 | { | ||
90 | unsigned int num_plts = 0; | ||
91 | unsigned int num_gots = 0; | ||
92 | int i; | ||
93 | |||
94 | /* | ||
95 | * Find the empty .got and .plt sections. | ||
96 | */ | ||
97 | for (i = 0; i < ehdr->e_shnum; i++) { | ||
98 | if (!strcmp(secstrings + sechdrs[i].sh_name, ".plt")) | ||
99 | mod->arch.plt.shdr = sechdrs + i; | ||
100 | else if (!strcmp(secstrings + sechdrs[i].sh_name, ".got")) | ||
101 | mod->arch.got.shdr = sechdrs + i; | ||
102 | else if (!strcmp(secstrings + sechdrs[i].sh_name, ".got.plt")) | ||
103 | mod->arch.got_plt.shdr = sechdrs + i; | ||
104 | } | ||
105 | |||
106 | if (!mod->arch.plt.shdr) { | ||
107 | pr_err("%s: module PLT section(s) missing\n", mod->name); | ||
108 | return -ENOEXEC; | ||
109 | } | ||
110 | if (!mod->arch.got.shdr) { | ||
111 | pr_err("%s: module GOT section(s) missing\n", mod->name); | ||
112 | return -ENOEXEC; | ||
113 | } | ||
114 | if (!mod->arch.got_plt.shdr) { | ||
115 | pr_err("%s: module GOT.PLT section(s) missing\n", mod->name); | ||
116 | return -ENOEXEC; | ||
117 | } | ||
118 | |||
119 | /* Calculate the maxinum number of entries */ | ||
120 | for (i = 0; i < ehdr->e_shnum; i++) { | ||
121 | Elf64_Rela *relas = (void *)ehdr + sechdrs[i].sh_offset; | ||
122 | int num_rela = sechdrs[i].sh_size / sizeof(Elf64_Rela); | ||
123 | Elf64_Shdr *dst_sec = sechdrs + sechdrs[i].sh_info; | ||
124 | |||
125 | if (sechdrs[i].sh_type != SHT_RELA) | ||
126 | continue; | ||
127 | |||
128 | /* ignore relocations that operate on non-exec sections */ | ||
129 | if (!(dst_sec->sh_flags & SHF_EXECINSTR)) | ||
130 | continue; | ||
131 | |||
132 | count_max_entries(relas, num_rela, &num_plts, &num_gots); | ||
133 | } | ||
134 | |||
135 | mod->arch.plt.shdr->sh_type = SHT_NOBITS; | ||
136 | mod->arch.plt.shdr->sh_flags = SHF_EXECINSTR | SHF_ALLOC; | ||
137 | mod->arch.plt.shdr->sh_addralign = L1_CACHE_BYTES; | ||
138 | mod->arch.plt.shdr->sh_size = (num_plts + 1) * sizeof(struct plt_entry); | ||
139 | mod->arch.plt.num_entries = 0; | ||
140 | mod->arch.plt.max_entries = num_plts; | ||
141 | |||
142 | mod->arch.got.shdr->sh_type = SHT_NOBITS; | ||
143 | mod->arch.got.shdr->sh_flags = SHF_ALLOC; | ||
144 | mod->arch.got.shdr->sh_addralign = L1_CACHE_BYTES; | ||
145 | mod->arch.got.shdr->sh_size = (num_gots + 1) * sizeof(struct got_entry); | ||
146 | mod->arch.got.num_entries = 0; | ||
147 | mod->arch.got.max_entries = num_gots; | ||
148 | |||
149 | mod->arch.got_plt.shdr->sh_type = SHT_NOBITS; | ||
150 | mod->arch.got_plt.shdr->sh_flags = SHF_ALLOC; | ||
151 | mod->arch.got_plt.shdr->sh_addralign = L1_CACHE_BYTES; | ||
152 | mod->arch.got_plt.shdr->sh_size = (num_plts + 1) * sizeof(struct got_entry); | ||
153 | mod->arch.got_plt.num_entries = 0; | ||
154 | mod->arch.got_plt.max_entries = num_plts; | ||
155 | return 0; | ||
156 | } | ||
diff --git a/arch/riscv/kernel/module.c b/arch/riscv/kernel/module.c index e0f05034fc21..5dddba301d0a 100644 --- a/arch/riscv/kernel/module.c +++ b/arch/riscv/kernel/module.c | |||
@@ -49,6 +49,39 @@ static int apply_r_riscv_jal_rela(struct module *me, u32 *location, | |||
49 | return 0; | 49 | return 0; |
50 | } | 50 | } |
51 | 51 | ||
52 | static int apply_r_riscv_rcv_branch_rela(struct module *me, u32 *location, | ||
53 | Elf_Addr v) | ||
54 | { | ||
55 | s64 offset = (void *)v - (void *)location; | ||
56 | u16 imm8 = (offset & 0x100) << (12 - 8); | ||
57 | u16 imm7_6 = (offset & 0xc0) >> (6 - 5); | ||
58 | u16 imm5 = (offset & 0x20) >> (5 - 2); | ||
59 | u16 imm4_3 = (offset & 0x18) << (12 - 5); | ||
60 | u16 imm2_1 = (offset & 0x6) << (12 - 10); | ||
61 | |||
62 | *(u16 *)location = (*(u16 *)location & 0xe383) | | ||
63 | imm8 | imm7_6 | imm5 | imm4_3 | imm2_1; | ||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | static int apply_r_riscv_rvc_jump_rela(struct module *me, u32 *location, | ||
68 | Elf_Addr v) | ||
69 | { | ||
70 | s64 offset = (void *)v - (void *)location; | ||
71 | u16 imm11 = (offset & 0x800) << (12 - 11); | ||
72 | u16 imm10 = (offset & 0x400) >> (10 - 8); | ||
73 | u16 imm9_8 = (offset & 0x300) << (12 - 11); | ||
74 | u16 imm7 = (offset & 0x80) >> (7 - 6); | ||
75 | u16 imm6 = (offset & 0x40) << (12 - 11); | ||
76 | u16 imm5 = (offset & 0x20) >> (5 - 2); | ||
77 | u16 imm4 = (offset & 0x10) << (12 - 5); | ||
78 | u16 imm3_1 = (offset & 0xe) << (12 - 10); | ||
79 | |||
80 | *(u16 *)location = (*(u16 *)location & 0xe003) | | ||
81 | imm11 | imm10 | imm9_8 | imm7 | imm6 | imm5 | imm4 | imm3_1; | ||
82 | return 0; | ||
83 | } | ||
84 | |||
52 | static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location, | 85 | static int apply_r_riscv_pcrel_hi20_rela(struct module *me, u32 *location, |
53 | Elf_Addr v) | 86 | Elf_Addr v) |
54 | { | 87 | { |
@@ -92,6 +125,67 @@ static int apply_r_riscv_pcrel_lo12_s_rela(struct module *me, u32 *location, | |||
92 | return 0; | 125 | return 0; |
93 | } | 126 | } |
94 | 127 | ||
128 | static int apply_r_riscv_hi20_rela(struct module *me, u32 *location, | ||
129 | Elf_Addr v) | ||
130 | { | ||
131 | s32 hi20; | ||
132 | |||
133 | if (IS_ENABLED(CMODEL_MEDLOW)) { | ||
134 | pr_err( | ||
135 | "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", | ||
136 | me->name, v, location); | ||
137 | return -EINVAL; | ||
138 | } | ||
139 | |||
140 | hi20 = ((s32)v + 0x800) & 0xfffff000; | ||
141 | *location = (*location & 0xfff) | hi20; | ||
142 | return 0; | ||
143 | } | ||
144 | |||
145 | static int apply_r_riscv_lo12_i_rela(struct module *me, u32 *location, | ||
146 | Elf_Addr v) | ||
147 | { | ||
148 | /* Skip medlow checking because of filtering by HI20 already */ | ||
149 | s32 hi20 = ((s32)v + 0x800) & 0xfffff000; | ||
150 | s32 lo12 = ((s32)v - hi20); | ||
151 | *location = (*location & 0xfffff) | ((lo12 & 0xfff) << 20); | ||
152 | return 0; | ||
153 | } | ||
154 | |||
155 | static int apply_r_riscv_lo12_s_rela(struct module *me, u32 *location, | ||
156 | Elf_Addr v) | ||
157 | { | ||
158 | /* Skip medlow checking because of filtering by HI20 already */ | ||
159 | s32 hi20 = ((s32)v + 0x800) & 0xfffff000; | ||
160 | s32 lo12 = ((s32)v - hi20); | ||
161 | u32 imm11_5 = (lo12 & 0xfe0) << (31 - 11); | ||
162 | u32 imm4_0 = (lo12 & 0x1f) << (11 - 4); | ||
163 | *location = (*location & 0x1fff07f) | imm11_5 | imm4_0; | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static int apply_r_riscv_got_hi20_rela(struct module *me, u32 *location, | ||
168 | Elf_Addr v) | ||
169 | { | ||
170 | s64 offset = (void *)v - (void *)location; | ||
171 | s32 hi20; | ||
172 | |||
173 | /* Always emit the got entry */ | ||
174 | if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) { | ||
175 | offset = module_emit_got_entry(me, v); | ||
176 | offset = (void *)offset - (void *)location; | ||
177 | } else { | ||
178 | pr_err( | ||
179 | "%s: can not generate the GOT entry for symbol = %016llx from PC = %p\n", | ||
180 | me->name, v, location); | ||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | hi20 = (offset + 0x800) & 0xfffff000; | ||
185 | *location = (*location & 0xfff) | hi20; | ||
186 | return 0; | ||
187 | } | ||
188 | |||
95 | static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location, | 189 | static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location, |
96 | Elf_Addr v) | 190 | Elf_Addr v) |
97 | { | 191 | { |
@@ -100,6 +194,33 @@ static int apply_r_riscv_call_plt_rela(struct module *me, u32 *location, | |||
100 | u32 hi20, lo12; | 194 | u32 hi20, lo12; |
101 | 195 | ||
102 | if (offset != fill_v) { | 196 | if (offset != fill_v) { |
197 | /* Only emit the plt entry if offset over 32-bit range */ | ||
198 | if (IS_ENABLED(CONFIG_MODULE_SECTIONS)) { | ||
199 | offset = module_emit_plt_entry(me, v); | ||
200 | offset = (void *)offset - (void *)location; | ||
201 | } else { | ||
202 | pr_err( | ||
203 | "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", | ||
204 | me->name, v, location); | ||
205 | return -EINVAL; | ||
206 | } | ||
207 | } | ||
208 | |||
209 | hi20 = (offset + 0x800) & 0xfffff000; | ||
210 | lo12 = (offset - hi20) & 0xfff; | ||
211 | *location = (*location & 0xfff) | hi20; | ||
212 | *(location + 1) = (*(location + 1) & 0xfffff) | (lo12 << 20); | ||
213 | return 0; | ||
214 | } | ||
215 | |||
216 | static int apply_r_riscv_call_rela(struct module *me, u32 *location, | ||
217 | Elf_Addr v) | ||
218 | { | ||
219 | s64 offset = (void *)v - (void *)location; | ||
220 | s32 fill_v = offset; | ||
221 | u32 hi20, lo12; | ||
222 | |||
223 | if (offset != fill_v) { | ||
103 | pr_err( | 224 | pr_err( |
104 | "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", | 225 | "%s: target %016llx can not be addressed by the 32-bit offset from PC = %p\n", |
105 | me->name, v, location); | 226 | me->name, v, location); |
@@ -119,16 +240,49 @@ static int apply_r_riscv_relax_rela(struct module *me, u32 *location, | |||
119 | return 0; | 240 | return 0; |
120 | } | 241 | } |
121 | 242 | ||
243 | static int apply_r_riscv_align_rela(struct module *me, u32 *location, | ||
244 | Elf_Addr v) | ||
245 | { | ||
246 | pr_err( | ||
247 | "%s: The unexpected relocation type 'R_RISCV_ALIGN' from PC = %p\n", | ||
248 | me->name, location); | ||
249 | return -EINVAL; | ||
250 | } | ||
251 | |||
252 | static int apply_r_riscv_add32_rela(struct module *me, u32 *location, | ||
253 | Elf_Addr v) | ||
254 | { | ||
255 | *(u32 *)location += (*(u32 *)v); | ||
256 | return 0; | ||
257 | } | ||
258 | |||
259 | static int apply_r_riscv_sub32_rela(struct module *me, u32 *location, | ||
260 | Elf_Addr v) | ||
261 | { | ||
262 | *(u32 *)location -= (*(u32 *)v); | ||
263 | return 0; | ||
264 | } | ||
265 | |||
122 | static int (*reloc_handlers_rela[]) (struct module *me, u32 *location, | 266 | static int (*reloc_handlers_rela[]) (struct module *me, u32 *location, |
123 | Elf_Addr v) = { | 267 | Elf_Addr v) = { |
124 | [R_RISCV_64] = apply_r_riscv_64_rela, | 268 | [R_RISCV_64] = apply_r_riscv_64_rela, |
125 | [R_RISCV_BRANCH] = apply_r_riscv_branch_rela, | 269 | [R_RISCV_BRANCH] = apply_r_riscv_branch_rela, |
126 | [R_RISCV_JAL] = apply_r_riscv_jal_rela, | 270 | [R_RISCV_JAL] = apply_r_riscv_jal_rela, |
271 | [R_RISCV_RVC_BRANCH] = apply_r_riscv_rcv_branch_rela, | ||
272 | [R_RISCV_RVC_JUMP] = apply_r_riscv_rvc_jump_rela, | ||
127 | [R_RISCV_PCREL_HI20] = apply_r_riscv_pcrel_hi20_rela, | 273 | [R_RISCV_PCREL_HI20] = apply_r_riscv_pcrel_hi20_rela, |
128 | [R_RISCV_PCREL_LO12_I] = apply_r_riscv_pcrel_lo12_i_rela, | 274 | [R_RISCV_PCREL_LO12_I] = apply_r_riscv_pcrel_lo12_i_rela, |
129 | [R_RISCV_PCREL_LO12_S] = apply_r_riscv_pcrel_lo12_s_rela, | 275 | [R_RISCV_PCREL_LO12_S] = apply_r_riscv_pcrel_lo12_s_rela, |
276 | [R_RISCV_HI20] = apply_r_riscv_hi20_rela, | ||
277 | [R_RISCV_LO12_I] = apply_r_riscv_lo12_i_rela, | ||
278 | [R_RISCV_LO12_S] = apply_r_riscv_lo12_s_rela, | ||
279 | [R_RISCV_GOT_HI20] = apply_r_riscv_got_hi20_rela, | ||
130 | [R_RISCV_CALL_PLT] = apply_r_riscv_call_plt_rela, | 280 | [R_RISCV_CALL_PLT] = apply_r_riscv_call_plt_rela, |
281 | [R_RISCV_CALL] = apply_r_riscv_call_rela, | ||
131 | [R_RISCV_RELAX] = apply_r_riscv_relax_rela, | 282 | [R_RISCV_RELAX] = apply_r_riscv_relax_rela, |
283 | [R_RISCV_ALIGN] = apply_r_riscv_align_rela, | ||
284 | [R_RISCV_ADD32] = apply_r_riscv_add32_rela, | ||
285 | [R_RISCV_SUB32] = apply_r_riscv_sub32_rela, | ||
132 | }; | 286 | }; |
133 | 287 | ||
134 | int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, | 288 | int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, |
@@ -184,25 +338,38 @@ int apply_relocate_add(Elf_Shdr *sechdrs, const char *strtab, | |||
184 | u64 hi20_loc = | 338 | u64 hi20_loc = |
185 | sechdrs[sechdrs[relsec].sh_info].sh_addr | 339 | sechdrs[sechdrs[relsec].sh_info].sh_addr |
186 | + rel[j].r_offset; | 340 | + rel[j].r_offset; |
187 | /* Find the corresponding HI20 PC-relative relocation entry */ | 341 | u32 hi20_type = ELF_RISCV_R_TYPE(rel[j].r_info); |
188 | if (hi20_loc == sym->st_value) { | 342 | |
343 | /* Find the corresponding HI20 relocation entry */ | ||
344 | if (hi20_loc == sym->st_value | ||
345 | && (hi20_type == R_RISCV_PCREL_HI20 | ||
346 | || hi20_type == R_RISCV_GOT_HI20)) { | ||
347 | s32 hi20, lo12; | ||
189 | Elf_Sym *hi20_sym = | 348 | Elf_Sym *hi20_sym = |
190 | (Elf_Sym *)sechdrs[symindex].sh_addr | 349 | (Elf_Sym *)sechdrs[symindex].sh_addr |
191 | + ELF_RISCV_R_SYM(rel[j].r_info); | 350 | + ELF_RISCV_R_SYM(rel[j].r_info); |
192 | u64 hi20_sym_val = | 351 | u64 hi20_sym_val = |
193 | hi20_sym->st_value | 352 | hi20_sym->st_value |
194 | + rel[j].r_addend; | 353 | + rel[j].r_addend; |
354 | |||
195 | /* Calculate lo12 */ | 355 | /* Calculate lo12 */ |
196 | s64 offset = hi20_sym_val - hi20_loc; | 356 | u64 offset = hi20_sym_val - hi20_loc; |
197 | s32 hi20 = (offset + 0x800) & 0xfffff000; | 357 | if (IS_ENABLED(CONFIG_MODULE_SECTIONS) |
198 | s32 lo12 = offset - hi20; | 358 | && hi20_type == R_RISCV_GOT_HI20) { |
359 | offset = module_emit_got_entry( | ||
360 | me, hi20_sym_val); | ||
361 | offset = offset - hi20_loc; | ||
362 | } | ||
363 | hi20 = (offset + 0x800) & 0xfffff000; | ||
364 | lo12 = offset - hi20; | ||
199 | v = lo12; | 365 | v = lo12; |
366 | |||
200 | break; | 367 | break; |
201 | } | 368 | } |
202 | } | 369 | } |
203 | if (j == sechdrs[relsec].sh_size / sizeof(*rel)) { | 370 | if (j == sechdrs[relsec].sh_size / sizeof(*rel)) { |
204 | pr_err( | 371 | pr_err( |
205 | "%s: Can not find HI20 PC-relative relocation information\n", | 372 | "%s: Can not find HI20 relocation information\n", |
206 | me->name); | 373 | me->name); |
207 | return -EINVAL; | 374 | return -EINVAL; |
208 | } | 375 | } |
diff --git a/arch/riscv/kernel/module.lds b/arch/riscv/kernel/module.lds new file mode 100644 index 000000000000..295ecfb341a2 --- /dev/null +++ b/arch/riscv/kernel/module.lds | |||
@@ -0,0 +1,8 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* Copyright (C) 2017 Andes Technology Corporation */ | ||
3 | |||
4 | SECTIONS { | ||
5 | .plt (NOLOAD) : { BYTE(0) } | ||
6 | .got (NOLOAD) : { BYTE(0) } | ||
7 | .got.plt (NOLOAD) : { BYTE(0) } | ||
8 | } | ||
diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c index 559aae781154..a4b1d94371a0 100644 --- a/arch/riscv/kernel/stacktrace.c +++ b/arch/riscv/kernel/stacktrace.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/sched/debug.h> | 18 | #include <linux/sched/debug.h> |
19 | #include <linux/sched/task_stack.h> | 19 | #include <linux/sched/task_stack.h> |
20 | #include <linux/stacktrace.h> | 20 | #include <linux/stacktrace.h> |
21 | #include <linux/ftrace.h> | ||
21 | 22 | ||
22 | #ifdef CONFIG_FRAME_POINTER | 23 | #ifdef CONFIG_FRAME_POINTER |
23 | 24 | ||
@@ -63,7 +64,12 @@ static void notrace walk_stackframe(struct task_struct *task, | |||
63 | frame = (struct stackframe *)fp - 1; | 64 | frame = (struct stackframe *)fp - 1; |
64 | sp = fp; | 65 | sp = fp; |
65 | fp = frame->fp; | 66 | fp = frame->fp; |
67 | #ifdef HAVE_FUNCTION_GRAPH_RET_ADDR_PTR | ||
68 | pc = ftrace_graph_ret_addr(current, NULL, frame->ra, | ||
69 | (unsigned long *)(fp - 8)); | ||
70 | #else | ||
66 | pc = frame->ra - 0x4; | 71 | pc = frame->ra - 0x4; |
72 | #endif | ||
67 | } | 73 | } |
68 | } | 74 | } |
69 | 75 | ||
diff --git a/scripts/recordmcount.pl b/scripts/recordmcount.pl index c74ecc6504e8..191eb949d52c 100755 --- a/scripts/recordmcount.pl +++ b/scripts/recordmcount.pl | |||
@@ -368,6 +368,11 @@ if ($arch eq "x86_64") { | |||
368 | } elsif ($arch eq "microblaze") { | 368 | } elsif ($arch eq "microblaze") { |
369 | # Microblaze calls '_mcount' instead of plain 'mcount'. | 369 | # Microblaze calls '_mcount' instead of plain 'mcount'. |
370 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; | 370 | $mcount_regex = "^\\s*([0-9a-fA-F]+):.*\\s_mcount\$"; |
371 | } elsif ($arch eq "riscv") { | ||
372 | $function_regex = "^([0-9a-fA-F]+)\\s+<([^.0-9][0-9a-zA-Z_\\.]+)>:"; | ||
373 | $mcount_regex = "^\\s*([0-9a-fA-F]+):\\sR_RISCV_CALL\\s_mcount\$"; | ||
374 | $type = ".quad"; | ||
375 | $alignment = 2; | ||
371 | } else { | 376 | } else { |
372 | die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; | 377 | die "Arch $arch is not supported with CONFIG_FTRACE_MCOUNT_RECORD"; |
373 | } | 378 | } |