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.c82
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
23int show_unhandled_signals = 1; 25int 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
309int 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
334void 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
368static 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
306void data_exception(struct pt_regs *regs) 376void 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