diff options
Diffstat (limited to 'arch/s390/kernel/traps.c')
-rw-r--r-- | arch/s390/kernel/traps.c | 153 |
1 files changed, 2 insertions, 151 deletions
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index f081cf1157c3..8be11c22ed17 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -26,7 +26,6 @@ int show_unhandled_signals = 1; | |||
26 | 26 | ||
27 | static inline void __user *get_trap_ip(struct pt_regs *regs) | 27 | static inline void __user *get_trap_ip(struct pt_regs *regs) |
28 | { | 28 | { |
29 | #ifdef CONFIG_64BIT | ||
30 | unsigned long address; | 29 | unsigned long address; |
31 | 30 | ||
32 | if (regs->int_code & 0x200) | 31 | if (regs->int_code & 0x200) |
@@ -35,10 +34,6 @@ static inline void __user *get_trap_ip(struct pt_regs *regs) | |||
35 | address = regs->psw.addr; | 34 | address = regs->psw.addr; |
36 | return (void __user *) | 35 | return (void __user *) |
37 | ((address - (regs->int_code >> 16)) & PSW_ADDR_INSN); | 36 | ((address - (regs->int_code >> 16)) & PSW_ADDR_INSN); |
38 | #else | ||
39 | return (void __user *) | ||
40 | ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN); | ||
41 | #endif | ||
42 | } | 37 | } |
43 | 38 | ||
44 | static inline void report_user_fault(struct pt_regs *regs, int signr) | 39 | static inline void report_user_fault(struct pt_regs *regs, int signr) |
@@ -153,11 +148,8 @@ DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC, | |||
153 | "privileged operation") | 148 | "privileged operation") |
154 | DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, | 149 | DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, |
155 | "special operation exception") | 150 | "special operation exception") |
156 | |||
157 | #ifdef CONFIG_64BIT | ||
158 | DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, | 151 | DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, |
159 | "transaction constraint exception") | 152 | "transaction constraint exception") |
160 | #endif | ||
161 | 153 | ||
162 | static inline void do_fp_trap(struct pt_regs *regs, int fpc) | 154 | static inline void do_fp_trap(struct pt_regs *regs, int fpc) |
163 | { | 155 | { |
@@ -211,29 +203,6 @@ void illegal_op(struct pt_regs *regs) | |||
211 | } else if (*((__u16 *) opcode) == UPROBE_SWBP_INSN) { | 203 | } else if (*((__u16 *) opcode) == UPROBE_SWBP_INSN) { |
212 | is_uprobe_insn = 1; | 204 | is_uprobe_insn = 1; |
213 | #endif | 205 | #endif |
214 | #ifdef CONFIG_MATHEMU | ||
215 | } else if (opcode[0] == 0xb3) { | ||
216 | if (get_user(*((__u16 *) (opcode+2)), location+1)) | ||
217 | return; | ||
218 | signal = math_emu_b3(opcode, regs); | ||
219 | } else if (opcode[0] == 0xed) { | ||
220 | if (get_user(*((__u32 *) (opcode+2)), | ||
221 | (__u32 __user *)(location+1))) | ||
222 | return; | ||
223 | signal = math_emu_ed(opcode, regs); | ||
224 | } else if (*((__u16 *) opcode) == 0xb299) { | ||
225 | if (get_user(*((__u16 *) (opcode+2)), location+1)) | ||
226 | return; | ||
227 | signal = math_emu_srnm(opcode, regs); | ||
228 | } else if (*((__u16 *) opcode) == 0xb29c) { | ||
229 | if (get_user(*((__u16 *) (opcode+2)), location+1)) | ||
230 | return; | ||
231 | signal = math_emu_stfpc(opcode, regs); | ||
232 | } else if (*((__u16 *) opcode) == 0xb29d) { | ||
233 | if (get_user(*((__u16 *) (opcode+2)), location+1)) | ||
234 | return; | ||
235 | signal = math_emu_lfpc(opcode, regs); | ||
236 | #endif | ||
237 | } else | 206 | } else |
238 | signal = SIGILL; | 207 | signal = SIGILL; |
239 | } | 208 | } |
@@ -247,71 +216,14 @@ void illegal_op(struct pt_regs *regs) | |||
247 | 3, SIGTRAP) != NOTIFY_STOP) | 216 | 3, SIGTRAP) != NOTIFY_STOP) |
248 | signal = SIGILL; | 217 | signal = SIGILL; |
249 | } | 218 | } |
250 | |||
251 | #ifdef CONFIG_MATHEMU | ||
252 | if (signal == SIGFPE) | ||
253 | do_fp_trap(regs, current->thread.fp_regs.fpc); | ||
254 | else if (signal == SIGSEGV) | ||
255 | do_trap(regs, signal, SEGV_MAPERR, "user address fault"); | ||
256 | else | ||
257 | #endif | ||
258 | if (signal) | 219 | if (signal) |
259 | do_trap(regs, signal, ILL_ILLOPC, "illegal operation"); | 220 | do_trap(regs, signal, ILL_ILLOPC, "illegal operation"); |
260 | } | 221 | } |
261 | NOKPROBE_SYMBOL(illegal_op); | 222 | NOKPROBE_SYMBOL(illegal_op); |
262 | 223 | ||
263 | #ifdef CONFIG_MATHEMU | ||
264 | void specification_exception(struct pt_regs *regs) | ||
265 | { | ||
266 | __u8 opcode[6]; | ||
267 | __u16 __user *location = NULL; | ||
268 | int signal = 0; | ||
269 | |||
270 | location = (__u16 __user *) get_trap_ip(regs); | ||
271 | |||
272 | if (user_mode(regs)) { | ||
273 | get_user(*((__u16 *) opcode), location); | ||
274 | switch (opcode[0]) { | ||
275 | case 0x28: /* LDR Rx,Ry */ | ||
276 | signal = math_emu_ldr(opcode); | ||
277 | break; | ||
278 | case 0x38: /* LER Rx,Ry */ | ||
279 | signal = math_emu_ler(opcode); | ||
280 | break; | ||
281 | case 0x60: /* STD R,D(X,B) */ | ||
282 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
283 | signal = math_emu_std(opcode, regs); | ||
284 | break; | ||
285 | case 0x68: /* LD R,D(X,B) */ | ||
286 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
287 | signal = math_emu_ld(opcode, regs); | ||
288 | break; | ||
289 | case 0x70: /* STE R,D(X,B) */ | ||
290 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
291 | signal = math_emu_ste(opcode, regs); | ||
292 | break; | ||
293 | case 0x78: /* LE R,D(X,B) */ | ||
294 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
295 | signal = math_emu_le(opcode, regs); | ||
296 | break; | ||
297 | default: | ||
298 | signal = SIGILL; | ||
299 | break; | ||
300 | } | ||
301 | } else | ||
302 | signal = SIGILL; | ||
303 | |||
304 | if (signal == SIGFPE) | ||
305 | do_fp_trap(regs, current->thread.fp_regs.fpc); | ||
306 | else if (signal) | ||
307 | do_trap(regs, signal, ILL_ILLOPN, "specification exception"); | ||
308 | } | ||
309 | #else | ||
310 | DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, | 224 | DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, |
311 | "specification exception"); | 225 | "specification exception"); |
312 | #endif | ||
313 | 226 | ||
314 | #ifdef CONFIG_64BIT | ||
315 | int alloc_vector_registers(struct task_struct *tsk) | 227 | int alloc_vector_registers(struct task_struct *tsk) |
316 | { | 228 | { |
317 | __vector128 *vxrs; | 229 | __vector128 *vxrs; |
@@ -377,7 +289,6 @@ static int __init disable_vector_extension(char *str) | |||
377 | return 1; | 289 | return 1; |
378 | } | 290 | } |
379 | __setup("novx", disable_vector_extension); | 291 | __setup("novx", disable_vector_extension); |
380 | #endif | ||
381 | 292 | ||
382 | void data_exception(struct pt_regs *regs) | 293 | void data_exception(struct pt_regs *regs) |
383 | { | 294 | { |
@@ -386,65 +297,7 @@ void data_exception(struct pt_regs *regs) | |||
386 | 297 | ||
387 | location = get_trap_ip(regs); | 298 | location = get_trap_ip(regs); |
388 | 299 | ||
389 | if (MACHINE_HAS_IEEE) | 300 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); |
390 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); | ||
391 | |||
392 | #ifdef CONFIG_MATHEMU | ||
393 | else if (user_mode(regs)) { | ||
394 | __u8 opcode[6]; | ||
395 | get_user(*((__u16 *) opcode), location); | ||
396 | switch (opcode[0]) { | ||
397 | case 0x28: /* LDR Rx,Ry */ | ||
398 | signal = math_emu_ldr(opcode); | ||
399 | break; | ||
400 | case 0x38: /* LER Rx,Ry */ | ||
401 | signal = math_emu_ler(opcode); | ||
402 | break; | ||
403 | case 0x60: /* STD R,D(X,B) */ | ||
404 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
405 | signal = math_emu_std(opcode, regs); | ||
406 | break; | ||
407 | case 0x68: /* LD R,D(X,B) */ | ||
408 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
409 | signal = math_emu_ld(opcode, regs); | ||
410 | break; | ||
411 | case 0x70: /* STE R,D(X,B) */ | ||
412 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
413 | signal = math_emu_ste(opcode, regs); | ||
414 | break; | ||
415 | case 0x78: /* LE R,D(X,B) */ | ||
416 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
417 | signal = math_emu_le(opcode, regs); | ||
418 | break; | ||
419 | case 0xb3: | ||
420 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
421 | signal = math_emu_b3(opcode, regs); | ||
422 | break; | ||
423 | case 0xed: | ||
424 | get_user(*((__u32 *) (opcode+2)), | ||
425 | (__u32 __user *)(location+1)); | ||
426 | signal = math_emu_ed(opcode, regs); | ||
427 | break; | ||
428 | case 0xb2: | ||
429 | if (opcode[1] == 0x99) { | ||
430 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
431 | signal = math_emu_srnm(opcode, regs); | ||
432 | } else if (opcode[1] == 0x9c) { | ||
433 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
434 | signal = math_emu_stfpc(opcode, regs); | ||
435 | } else if (opcode[1] == 0x9d) { | ||
436 | get_user(*((__u16 *) (opcode+2)), location+1); | ||
437 | signal = math_emu_lfpc(opcode, regs); | ||
438 | } else | ||
439 | signal = SIGILL; | ||
440 | break; | ||
441 | default: | ||
442 | signal = SIGILL; | ||
443 | break; | ||
444 | } | ||
445 | } | ||
446 | #endif | ||
447 | #ifdef CONFIG_64BIT | ||
448 | /* Check for vector register enablement */ | 301 | /* Check for vector register enablement */ |
449 | if (MACHINE_HAS_VX && !current->thread.vxrs && | 302 | if (MACHINE_HAS_VX && !current->thread.vxrs && |
450 | (current->thread.fp_regs.fpc & FPC_DXC_MASK) == 0xfe00) { | 303 | (current->thread.fp_regs.fpc & FPC_DXC_MASK) == 0xfe00) { |
@@ -454,13 +307,11 @@ void data_exception(struct pt_regs *regs) | |||
454 | clear_pt_regs_flag(regs, PIF_PER_TRAP); | 307 | clear_pt_regs_flag(regs, PIF_PER_TRAP); |
455 | return; | 308 | return; |
456 | } | 309 | } |
457 | #endif | ||
458 | |||
459 | if (current->thread.fp_regs.fpc & FPC_DXC_MASK) | 310 | if (current->thread.fp_regs.fpc & FPC_DXC_MASK) |
460 | signal = SIGFPE; | 311 | signal = SIGFPE; |
461 | else | 312 | else |
462 | signal = SIGILL; | 313 | signal = SIGILL; |
463 | if (signal == SIGFPE) | 314 | if (signal == SIGFPE) |
464 | do_fp_trap(regs, current->thread.fp_regs.fpc); | 315 | do_fp_trap(regs, current->thread.fp_regs.fpc); |
465 | else if (signal) | 316 | else if (signal) |
466 | do_trap(regs, signal, ILL_ILLOPN, "data exception"); | 317 | do_trap(regs, signal, ILL_ILLOPN, "data exception"); |