aboutsummaryrefslogtreecommitdiffstats
path: root/arch/frv/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/frv/kernel/traps.c')
-rw-r--r--arch/frv/kernel/traps.c240
1 files changed, 234 insertions, 6 deletions
diff --git a/arch/frv/kernel/traps.c b/arch/frv/kernel/traps.c
index 2e6098c8557..a40df80b2eb 100644
--- a/arch/frv/kernel/traps.c
+++ b/arch/frv/kernel/traps.c
@@ -49,7 +49,7 @@ asmlinkage void insn_access_error(unsigned long esfr1, unsigned long epcr0, unsi
49 info.si_signo = SIGSEGV; 49 info.si_signo = SIGSEGV;
50 info.si_code = SEGV_ACCERR; 50 info.si_code = SEGV_ACCERR;
51 info.si_errno = 0; 51 info.si_errno = 0;
52 info.si_addr = (void *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc); 52 info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
53 53
54 force_sig_info(info.si_signo, &info, current); 54 force_sig_info(info.si_signo, &info, current);
55} /* end insn_access_error() */ 55} /* end insn_access_error() */
@@ -73,7 +73,7 @@ asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, un
73 epcr0, esr0, esfr1); 73 epcr0, esr0, esfr1);
74 74
75 info.si_errno = 0; 75 info.si_errno = 0;
76 info.si_addr = (void *) ((epcr0 & EPCR0_PC) ? (epcr0 & EPCR0_PC) : __frame->pc); 76 info.si_addr = (void __user *) ((epcr0 & EPCR0_V) ? (epcr0 & EPCR0_PC) : __frame->pc);
77 77
78 switch (__frame->tbr & TBR_TT) { 78 switch (__frame->tbr & TBR_TT) {
79 case TBR_TT_ILLEGAL_INSTR: 79 case TBR_TT_ILLEGAL_INSTR:
@@ -102,6 +102,234 @@ asmlinkage void illegal_instruction(unsigned long esfr1, unsigned long epcr0, un
102 102
103/*****************************************************************************/ 103/*****************************************************************************/
104/* 104/*
105 * handle atomic operations with errors
106 * - arguments in gr8, gr9, gr10
107 * - original memory value placed in gr5
108 * - replacement memory value placed in gr9
109 */
110asmlinkage void atomic_operation(unsigned long esfr1, unsigned long epcr0,
111 unsigned long esr0)
112{
113 static DEFINE_SPINLOCK(atomic_op_lock);
114 unsigned long x, y, z;
115 unsigned long __user *p;
116 mm_segment_t oldfs;
117 siginfo_t info;
118 int ret;
119
120 y = 0;
121 z = 0;
122
123 oldfs = get_fs();
124 if (!user_mode(__frame))
125 set_fs(KERNEL_DS);
126
127 switch (__frame->tbr & TBR_TT) {
128 /* TIRA gr0,#120
129 * u32 __atomic_user_cmpxchg32(u32 *ptr, u32 test, u32 new)
130 */
131 case TBR_TT_ATOMIC_CMPXCHG32:
132 p = (unsigned long __user *) __frame->gr8;
133 x = __frame->gr9;
134 y = __frame->gr10;
135
136 for (;;) {
137 ret = get_user(z, p);
138 if (ret < 0)
139 goto error;
140
141 if (z != x)
142 goto done;
143
144 spin_lock_irq(&atomic_op_lock);
145
146 if (__get_user(z, p) == 0) {
147 if (z != x)
148 goto done2;
149
150 if (__put_user(y, p) == 0)
151 goto done2;
152 goto error2;
153 }
154
155 spin_unlock_irq(&atomic_op_lock);
156 }
157
158 /* TIRA gr0,#121
159 * u32 __atomic_kernel_xchg32(void *v, u32 new)
160 */
161 case TBR_TT_ATOMIC_XCHG32:
162 p = (unsigned long __user *) __frame->gr8;
163 y = __frame->gr9;
164
165 for (;;) {
166 ret = get_user(z, p);
167 if (ret < 0)
168 goto error;
169
170 spin_lock_irq(&atomic_op_lock);
171
172 if (__get_user(z, p) == 0) {
173 if (__put_user(y, p) == 0)
174 goto done2;
175 goto error2;
176 }
177
178 spin_unlock_irq(&atomic_op_lock);
179 }
180
181 /* TIRA gr0,#122
182 * ulong __atomic_kernel_XOR_return(ulong i, ulong *v)
183 */
184 case TBR_TT_ATOMIC_XOR:
185 p = (unsigned long __user *) __frame->gr8;
186 x = __frame->gr9;
187
188 for (;;) {
189 ret = get_user(z, p);
190 if (ret < 0)
191 goto error;
192
193 spin_lock_irq(&atomic_op_lock);
194
195 if (__get_user(z, p) == 0) {
196 y = x ^ z;
197 if (__put_user(y, p) == 0)
198 goto done2;
199 goto error2;
200 }
201
202 spin_unlock_irq(&atomic_op_lock);
203 }
204
205 /* TIRA gr0,#123
206 * ulong __atomic_kernel_OR_return(ulong i, ulong *v)
207 */
208 case TBR_TT_ATOMIC_OR:
209 p = (unsigned long __user *) __frame->gr8;
210 x = __frame->gr9;
211
212 for (;;) {
213 ret = get_user(z, p);
214 if (ret < 0)
215 goto error;
216
217 spin_lock_irq(&atomic_op_lock);
218
219 if (__get_user(z, p) == 0) {
220 y = x ^ z;
221 if (__put_user(y, p) == 0)
222 goto done2;
223 goto error2;
224 }
225
226 spin_unlock_irq(&atomic_op_lock);
227 }
228
229 /* TIRA gr0,#124
230 * ulong __atomic_kernel_AND_return(ulong i, ulong *v)
231 */
232 case TBR_TT_ATOMIC_AND:
233 p = (unsigned long __user *) __frame->gr8;
234 x = __frame->gr9;
235
236 for (;;) {
237 ret = get_user(z, p);
238 if (ret < 0)
239 goto error;
240
241 spin_lock_irq(&atomic_op_lock);
242
243 if (__get_user(z, p) == 0) {
244 y = x & z;
245 if (__put_user(y, p) == 0)
246 goto done2;
247 goto error2;
248 }
249
250 spin_unlock_irq(&atomic_op_lock);
251 }
252
253 /* TIRA gr0,#125
254 * int __atomic_user_sub_return(atomic_t *v, int i)
255 */
256 case TBR_TT_ATOMIC_SUB:
257 p = (unsigned long __user *) __frame->gr8;
258 x = __frame->gr9;
259
260 for (;;) {
261 ret = get_user(z, p);
262 if (ret < 0)
263 goto error;
264
265 spin_lock_irq(&atomic_op_lock);
266
267 if (__get_user(z, p) == 0) {
268 y = z - x;
269 if (__put_user(y, p) == 0)
270 goto done2;
271 goto error2;
272 }
273
274 spin_unlock_irq(&atomic_op_lock);
275 }
276
277 /* TIRA gr0,#126
278 * int __atomic_user_add_return(atomic_t *v, int i)
279 */
280 case TBR_TT_ATOMIC_ADD:
281 p = (unsigned long __user *) __frame->gr8;
282 x = __frame->gr9;
283
284 for (;;) {
285 ret = get_user(z, p);
286 if (ret < 0)
287 goto error;
288
289 spin_lock_irq(&atomic_op_lock);
290
291 if (__get_user(z, p) == 0) {
292 y = z + x;
293 if (__put_user(y, p) == 0)
294 goto done2;
295 goto error2;
296 }
297
298 spin_unlock_irq(&atomic_op_lock);
299 }
300
301 default:
302 BUG();
303 }
304
305done2:
306 spin_unlock_irq(&atomic_op_lock);
307done:
308 if (!user_mode(__frame))
309 set_fs(oldfs);
310 __frame->gr5 = z;
311 __frame->gr9 = y;
312 return;
313
314error2:
315 spin_unlock_irq(&atomic_op_lock);
316error:
317 if (!user_mode(__frame))
318 set_fs(oldfs);
319 __frame->pc -= 4;
320
321 die_if_kernel("-- Atomic Op Error --\n");
322
323 info.si_signo = SIGSEGV;
324 info.si_code = SEGV_ACCERR;
325 info.si_errno = 0;
326 info.si_addr = (void __user *) __frame->pc;
327
328 force_sig_info(info.si_signo, &info, current);
329}
330
331/*****************************************************************************/
332/*
105 * 333 *
106 */ 334 */
107asmlinkage void media_exception(unsigned long msr0, unsigned long msr1) 335asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
@@ -116,7 +344,7 @@ asmlinkage void media_exception(unsigned long msr0, unsigned long msr1)
116 info.si_signo = SIGFPE; 344 info.si_signo = SIGFPE;
117 info.si_code = FPE_MDAOVF; 345 info.si_code = FPE_MDAOVF;
118 info.si_errno = 0; 346 info.si_errno = 0;
119 info.si_addr = (void *) __frame->pc; 347 info.si_addr = (void __user *) __frame->pc;
120 348
121 force_sig_info(info.si_signo, &info, current); 349 force_sig_info(info.si_signo, &info, current);
122} /* end media_exception() */ 350} /* end media_exception() */
@@ -156,7 +384,7 @@ asmlinkage void memory_access_exception(unsigned long esr0,
156 info.si_addr = NULL; 384 info.si_addr = NULL;
157 385
158 if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV)) 386 if ((esr0 & (ESRx_VALID | ESR0_EAV)) == (ESRx_VALID | ESR0_EAV))
159 info.si_addr = (void *) ear0; 387 info.si_addr = (void __user *) ear0;
160 388
161 force_sig_info(info.si_signo, &info, current); 389 force_sig_info(info.si_signo, &info, current);
162 390
@@ -185,7 +413,7 @@ asmlinkage void data_access_error(unsigned long esfr1, unsigned long esr15, unsi
185 info.si_signo = SIGSEGV; 413 info.si_signo = SIGSEGV;
186 info.si_code = SEGV_ACCERR; 414 info.si_code = SEGV_ACCERR;
187 info.si_errno = 0; 415 info.si_errno = 0;
188 info.si_addr = (void *) 416 info.si_addr = (void __user *)
189 (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0); 417 (((esr15 & (ESRx_VALID|ESR15_EAV)) == (ESRx_VALID|ESR15_EAV)) ? ear15 : 0);
190 418
191 force_sig_info(info.si_signo, &info, current); 419 force_sig_info(info.si_signo, &info, current);
@@ -219,7 +447,7 @@ asmlinkage void division_exception(unsigned long esfr1, unsigned long esr0, unsi
219 info.si_signo = SIGFPE; 447 info.si_signo = SIGFPE;
220 info.si_code = FPE_INTDIV; 448 info.si_code = FPE_INTDIV;
221 info.si_errno = 0; 449 info.si_errno = 0;
222 info.si_addr = (void *) __frame->pc; 450 info.si_addr = (void __user *) __frame->pc;
223 451
224 force_sig_info(info.si_signo, &info, current); 452 force_sig_info(info.si_signo, &info, current);
225} /* end division_exception() */ 453} /* end division_exception() */