aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/traps.c')
-rw-r--r--arch/s390/kernel/traps.c153
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
27static inline void __user *get_trap_ip(struct pt_regs *regs) 27static 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
44static inline void report_user_fault(struct pt_regs *regs, int signr) 39static 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")
154DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN, 149DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
155 "special operation exception") 150 "special operation exception")
156
157#ifdef CONFIG_64BIT
158DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN, 151DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN,
159 "transaction constraint exception") 152 "transaction constraint exception")
160#endif
161 153
162static inline void do_fp_trap(struct pt_regs *regs, int fpc) 154static 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}
261NOKPROBE_SYMBOL(illegal_op); 222NOKPROBE_SYMBOL(illegal_op);
262 223
263#ifdef CONFIG_MATHEMU
264void 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
310DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, 224DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
311 "specification exception"); 225 "specification exception");
312#endif
313 226
314#ifdef CONFIG_64BIT
315int alloc_vector_registers(struct task_struct *tsk) 227int 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
382void data_exception(struct pt_regs *regs) 293void 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");