s390: convert to generic entry
[linux-2.6-microblaze.git] / arch / s390 / kernel / traps.c
index 8d1e8a1..db7dd59 100644 (file)
@@ -13,6 +13,8 @@
  * 'Traps.c' handles hardware traps and faults after we have saved some
  * state in 'asm.s'.
  */
+#include "asm/irqflags.h"
+#include "asm/ptrace.h"
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 #include <linux/extable.h>
@@ -23,7 +25,9 @@
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 #include <linux/cpu.h>
+#include <linux/entry-common.h>
 #include <asm/fpu/api.h>
+#include <asm/vtime.h>
 #include "entry.h"
 
 static inline void __user *get_trap_ip(struct pt_regs *regs)
@@ -288,3 +292,64 @@ void __init trap_init(void)
        local_mcck_enable();
        test_monitor_call();
 }
+
+void noinstr __do_pgm_check(struct pt_regs *regs)
+{
+       unsigned long last_break = S390_lowcore.breaking_event_addr;
+       unsigned int trapnr, syscall_redirect = 0;
+       irqentry_state_t state;
+
+       regs->int_code = *(u32 *)&S390_lowcore.pgm_ilc;
+       regs->int_parm_long = S390_lowcore.trans_exc_code;
+
+       state = irqentry_enter(regs);
+
+       if (user_mode(regs)) {
+               update_timer_sys();
+               if (last_break < 4096)
+                       last_break = 1;
+               current->thread.last_break = last_break;
+               regs->args[0] = last_break;
+       }
+
+       if (S390_lowcore.pgm_code & 0x0200) {
+               /* transaction abort */
+               memcpy(&current->thread.trap_tdb, &S390_lowcore.pgm_tdb, 256);
+       }
+
+       if (S390_lowcore.pgm_code & PGM_INT_CODE_PER) {
+               if (user_mode(regs)) {
+                       struct per_event *ev = &current->thread.per_event;
+
+                       set_thread_flag(TIF_PER_TRAP);
+                       ev->address = S390_lowcore.per_address;
+                       ev->cause = *(u16 *)&S390_lowcore.per_code;
+                       ev->paid = S390_lowcore.per_access_id;
+               } else {
+                       /* PER event in kernel is kprobes */
+                       __arch_local_irq_ssm(regs->psw.mask & ~PSW_MASK_PER);
+                       do_per_trap(regs);
+                       goto out;
+               }
+       }
+
+       if (!irqs_disabled_flags(regs->psw.mask))
+               trace_hardirqs_on();
+       __arch_local_irq_ssm(regs->psw.mask & ~PSW_MASK_PER);
+
+       trapnr = regs->int_code & PGM_INT_CODE_MASK;
+       if (trapnr)
+               pgm_check_table[trapnr](regs);
+       syscall_redirect = user_mode(regs) && test_pt_regs_flag(regs, PIF_SYSCALL);
+out:
+       local_irq_disable();
+       irqentry_exit(regs, state);
+
+       if (syscall_redirect) {
+               enter_from_user_mode(regs);
+               local_irq_enable();
+               regs->orig_gpr2 = regs->gprs[2];
+               do_syscall(regs);
+               exit_to_user_mode();
+       }
+}