diff options
Diffstat (limited to 'arch/s390/kernel/traps.c')
-rw-r--r-- | arch/s390/kernel/traps.c | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index e3e06a4fdfce..9ff5ecba26ab 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -18,6 +18,8 @@ | |||
18 | #include <linux/ptrace.h> | 18 | #include <linux/ptrace.h> |
19 | #include <linux/sched.h> | 19 | #include <linux/sched.h> |
20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
21 | #include <linux/slab.h> | ||
22 | #include <asm/switch_to.h> | ||
21 | #include "entry.h" | 23 | #include "entry.h" |
22 | 24 | ||
23 | int show_unhandled_signals = 1; | 25 | int show_unhandled_signals = 1; |
@@ -303,6 +305,74 @@ DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN, | |||
303 | "specification exception"); | 305 | "specification exception"); |
304 | #endif | 306 | #endif |
305 | 307 | ||
308 | #ifdef CONFIG_64BIT | ||
309 | int alloc_vector_registers(struct task_struct *tsk) | ||
310 | { | ||
311 | __vector128 *vxrs; | ||
312 | int i; | ||
313 | |||
314 | /* Allocate vector register save area. */ | ||
315 | vxrs = kzalloc(sizeof(__vector128) * __NUM_VXRS, | ||
316 | GFP_KERNEL|__GFP_REPEAT); | ||
317 | if (!vxrs) | ||
318 | return -ENOMEM; | ||
319 | preempt_disable(); | ||
320 | if (tsk == current) | ||
321 | save_fp_regs(tsk->thread.fp_regs.fprs); | ||
322 | /* Copy the 16 floating point registers */ | ||
323 | for (i = 0; i < 16; i++) | ||
324 | *(freg_t *) &vxrs[i] = tsk->thread.fp_regs.fprs[i]; | ||
325 | tsk->thread.vxrs = vxrs; | ||
326 | if (tsk == current) { | ||
327 | __ctl_set_bit(0, 17); | ||
328 | restore_vx_regs(vxrs); | ||
329 | } | ||
330 | preempt_enable(); | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | void vector_exception(struct pt_regs *regs) | ||
335 | { | ||
336 | int si_code, vic; | ||
337 | |||
338 | if (!MACHINE_HAS_VX) { | ||
339 | do_trap(regs, SIGILL, ILL_ILLOPN, "illegal operation"); | ||
340 | return; | ||
341 | } | ||
342 | |||
343 | /* get vector interrupt code from fpc */ | ||
344 | asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc)); | ||
345 | vic = (current->thread.fp_regs.fpc & 0xf00) >> 8; | ||
346 | switch (vic) { | ||
347 | case 1: /* invalid vector operation */ | ||
348 | si_code = FPE_FLTINV; | ||
349 | break; | ||
350 | case 2: /* division by zero */ | ||
351 | si_code = FPE_FLTDIV; | ||
352 | break; | ||
353 | case 3: /* overflow */ | ||
354 | si_code = FPE_FLTOVF; | ||
355 | break; | ||
356 | case 4: /* underflow */ | ||
357 | si_code = FPE_FLTUND; | ||
358 | break; | ||
359 | case 5: /* inexact */ | ||
360 | si_code = FPE_FLTRES; | ||
361 | break; | ||
362 | default: /* unknown cause */ | ||
363 | si_code = 0; | ||
364 | } | ||
365 | do_trap(regs, SIGFPE, si_code, "vector exception"); | ||
366 | } | ||
367 | |||
368 | static int __init disable_vector_extension(char *str) | ||
369 | { | ||
370 | S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX; | ||
371 | return 1; | ||
372 | } | ||
373 | __setup("novx", disable_vector_extension); | ||
374 | #endif | ||
375 | |||
306 | void data_exception(struct pt_regs *regs) | 376 | void data_exception(struct pt_regs *regs) |
307 | { | 377 | { |
308 | __u16 __user *location; | 378 | __u16 __user *location; |
@@ -368,6 +438,18 @@ void data_exception(struct pt_regs *regs) | |||
368 | } | 438 | } |
369 | } | 439 | } |
370 | #endif | 440 | #endif |
441 | #ifdef CONFIG_64BIT | ||
442 | /* Check for vector register enablement */ | ||
443 | if (MACHINE_HAS_VX && !current->thread.vxrs && | ||
444 | (current->thread.fp_regs.fpc & FPC_DXC_MASK) == 0xfe00) { | ||
445 | alloc_vector_registers(current); | ||
446 | /* Vector data exception is suppressing, rewind psw. */ | ||
447 | regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16); | ||
448 | clear_pt_regs_flag(regs, PIF_PER_TRAP); | ||
449 | return; | ||
450 | } | ||
451 | #endif | ||
452 | |||
371 | if (current->thread.fp_regs.fpc & FPC_DXC_MASK) | 453 | if (current->thread.fp_regs.fpc & FPC_DXC_MASK) |
372 | signal = SIGFPE; | 454 | signal = SIGFPE; |
373 | else | 455 | else |