sparc64: Implement HAVE_CONTEXT_TRACKING
authorKirill Tkhai <tkhai@yandex.ru>
Sat, 14 Sep 2013 12:02:11 +0000 (16:02 +0400)
committerDavid S. Miller <davem@davemloft.net>
Thu, 14 Nov 2013 22:57:21 +0000 (14:57 -0800)
Mark the places when the system are in user or are in kernel.
This is used to make full dynticks system (tickless) --
CONFIG_NO_HZ_FULL dependence.

Signed-off-by: Kirill Tkhai <tkhai@yandex.ru>
CC: David Miller <davem@davemloft.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
14 files changed:
arch/sparc/Kconfig
arch/sparc/include/asm/thread_info_64.h
arch/sparc/kernel/entry.h
arch/sparc/kernel/kgdb_64.c
arch/sparc/kernel/kprobes.c
arch/sparc/kernel/process_64.c
arch/sparc/kernel/ptrace_64.c
arch/sparc/kernel/rtrap_64.S
arch/sparc/kernel/signal_64.c
arch/sparc/kernel/sys_sparc_64.c
arch/sparc/kernel/syscalls.S
arch/sparc/kernel/traps_64.c
arch/sparc/kernel/unaligned_64.c
arch/sparc/mm/fault_64.c

index 78c4fdb91bc57a425e9fd5978260088ef5072d34..01d77d78cd3263e774866ecf5de613bd04e65723 100644 (file)
@@ -64,6 +64,7 @@ config SPARC64
        select HAVE_DYNAMIC_FTRACE
        select HAVE_FTRACE_MCOUNT_RECORD
        select HAVE_SYSCALL_TRACEPOINTS
+       select HAVE_CONTEXT_TRACKING
        select HAVE_DEBUG_KMEMLEAK
        select RTC_DRV_CMOS
        select RTC_DRV_BQ4802
index d5e5042510790a1927e5f8b9a234038a599bcab7..5d9292ab10777bdae90bb8e61eb4d109090f8d15 100644 (file)
@@ -192,7 +192,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
 #define TIF_UNALIGNED          5       /* allowed to do unaligned accesses */
 /* flag bit 6 is available */
 #define TIF_32BIT              7       /* 32-bit binary */
-/* flag bit 8 is available */
+#define TIF_NOHZ               8       /* in adaptive nohz mode */
 #define TIF_SECCOMP            9       /* secure computing */
 #define TIF_SYSCALL_AUDIT      10      /* syscall auditing active */
 #define TIF_SYSCALL_TRACEPOINT 11      /* syscall tracepoint instrumentation */
@@ -210,6 +210,7 @@ register struct thread_info *current_thread_info_reg asm("g6");
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_UNALIGNED         (1<<TIF_UNALIGNED)
 #define _TIF_32BIT             (1<<TIF_32BIT)
+#define _TIF_NOHZ              (1<<TIF_NOHZ)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SYSCALL_TRACEPOINT        (1<<TIF_SYSCALL_TRACEPOINT)
index 9c179fbfb219c12b20f49e23aaf44db5567840e7..140966fbd30369448de54e9ea56e4b9022577b17 100644 (file)
@@ -88,7 +88,6 @@ extern asmlinkage void syscall_trace_leave(struct pt_regs *regs);
 
 extern void bad_trap_tl1(struct pt_regs *regs, long lvl);
 
-extern void do_fpe_common(struct pt_regs *regs);
 extern void do_fpieee(struct pt_regs *regs);
 extern void do_fpother(struct pt_regs *regs);
 extern void do_tof(struct pt_regs *regs);
index 53c0a82e60308d541271707681b046824ad79456..60b19f50c80a8f9d7f31b4b4105ed4fcded6a5ca 100644 (file)
@@ -159,11 +159,12 @@ int kgdb_arch_handle_exception(int e_vector, int signo, int err_code,
 
 asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs)
 {
+       enum ctx_state prev_state = exception_enter();
        unsigned long flags;
 
        if (user_mode(regs)) {
                bad_trap(regs, trap_level);
-               return;
+               goto out;
        }
 
        flushw_all();
@@ -171,6 +172,8 @@ asmlinkage void kgdb_trap(unsigned long trap_level, struct pt_regs *regs)
        local_irq_save(flags);
        kgdb_handle_exception(0x172, SIGTRAP, 0, regs);
        local_irq_restore(flags);
+out:
+       exception_exit(prev_state);
 }
 
 int kgdb_arch_init(void)
index e72212148d2a9e08dfe680f8500186b263a721f1..5a09fd315e5f5d558a4af17a3e43ac0b29954135 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/module.h>
 #include <linux/kdebug.h>
 #include <linux/slab.h>
+#include <linux/context_tracking.h>
 #include <asm/signal.h>
 #include <asm/cacheflush.h>
 #include <asm/uaccess.h>
@@ -418,12 +419,14 @@ int __kprobes kprobe_exceptions_notify(struct notifier_block *self,
 asmlinkage void __kprobes kprobe_trap(unsigned long trap_level,
                                      struct pt_regs *regs)
 {
+       enum ctx_state prev_state = exception_enter();
+
        BUG_ON(trap_level != 0x170 && trap_level != 0x171);
 
        if (user_mode(regs)) {
                local_irq_enable();
                bad_trap(regs, trap_level);
-               return;
+               goto out;
        }
 
        /* trap_level == 0x170 --> ta 0x70
@@ -433,6 +436,8 @@ asmlinkage void __kprobes kprobe_trap(unsigned long trap_level,
                       (trap_level == 0x170) ? "debug" : "debug_2",
                       regs, 0, trap_level, SIGTRAP) != NOTIFY_STOP)
                bad_trap(regs, trap_level);
+out:
+       exception_exit(prev_state);
 }
 
 /* Jprobes support.  */
index baebab215492966718fc8846e9f251ae3d20af82..32a280ec38c1d6edef71b5576ce474221726ec1e 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/elfcore.h>
 #include <linux/sysrq.h>
 #include <linux/nmi.h>
+#include <linux/context_tracking.h>
 
 #include <asm/uaccess.h>
 #include <asm/page.h>
@@ -557,6 +558,7 @@ void fault_in_user_windows(void)
 
 barf:
        set_thread_wsaved(window + 1);
+       user_exit();
        do_exit(SIGILL);
 }
 
index 773c1f2983ce3282c59a8f93efd62663218e741f..c13c9f25d83a0b11dc1d415bd556c1cd25d6f41b 100644 (file)
@@ -27,6 +27,7 @@
 #include <trace/syscall.h>
 #include <linux/compat.h>
 #include <linux/elf.h>
+#include <linux/context_tracking.h>
 
 #include <asm/asi.h>
 #include <asm/pgtable.h>
@@ -1066,6 +1067,9 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
        /* do the secure computing check first */
        secure_computing_strict(regs->u_regs[UREG_G1]);
 
+       if (test_thread_flag(TIF_NOHZ))
+               user_exit();
+
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                ret = tracehook_report_syscall_entry(regs);
 
@@ -1086,6 +1090,9 @@ asmlinkage int syscall_trace_enter(struct pt_regs *regs)
 
 asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 {
+       if (test_thread_flag(TIF_NOHZ))
+               user_exit();
+
        audit_syscall_exit(regs);
 
        if (unlikely(test_thread_flag(TIF_SYSCALL_TRACEPOINT)))
@@ -1093,4 +1100,7 @@ asmlinkage void syscall_trace_leave(struct pt_regs *regs)
 
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall_exit(regs, 0);
+
+       if (test_thread_flag(TIF_NOHZ))
+               user_enter();
 }
index afa2a9e3d0a0c6734785dfaafc68538d7e393b51..a954eb81881bf37d45fd01b22dc1e42839318f40 100644 (file)
 #define                RTRAP_PSTATE_IRQOFF     (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV)
 #define                RTRAP_PSTATE_AG_IRQOFF  (PSTATE_TSO|PSTATE_PEF|PSTATE_PRIV|PSTATE_AG)
 
+#ifdef CONFIG_CONTEXT_TRACKING
+# define SCHEDULE_USER schedule_user
+#else
+# define SCHEDULE_USER schedule
+#endif
+
                .text
                .align                  32
 __handle_preemption:
-               call                    schedule
+               call                    SCHEDULE_USER
                 wrpr                   %g0, RTRAP_PSTATE, %pstate
                ba,pt                   %xcc, __handle_preemption_continue
                 wrpr                   %g0, RTRAP_PSTATE_IRQOFF, %pstate
index 35923e8abd8234f8fe067c0ed4a5e6f49ee85cb8..cd91d010e6d3617456b7c743ee5efbb956c657d4 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/tty.h>
 #include <linux/binfmts.h>
 #include <linux/bitops.h>
+#include <linux/context_tracking.h>
 
 #include <asm/uaccess.h>
 #include <asm/ptrace.h>
@@ -43,6 +44,7 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
 {
        struct ucontext __user *ucp = (struct ucontext __user *)
                regs->u_regs[UREG_I0];
+       enum ctx_state prev_state = exception_enter();
        mc_gregset_t __user *grp;
        unsigned long pc, npc, tstate;
        unsigned long fp, i7;
@@ -129,16 +131,19 @@ asmlinkage void sparc64_set_context(struct pt_regs *regs)
        }
        if (err)
                goto do_sigsegv;
-
+out:
+       exception_exit(prev_state);
        return;
 do_sigsegv:
        force_sig(SIGSEGV, current);
+       goto out;
 }
 
 asmlinkage void sparc64_get_context(struct pt_regs *regs)
 {
        struct ucontext __user *ucp = (struct ucontext __user *)
                regs->u_regs[UREG_I0];
+       enum ctx_state prev_state = exception_enter();
        mc_gregset_t __user *grp;
        mcontext_t __user *mcp;
        unsigned long fp, i7;
@@ -220,10 +225,12 @@ asmlinkage void sparc64_get_context(struct pt_regs *regs)
        }
        if (err)
                goto do_sigsegv;
-
+out:
+       exception_exit(prev_state);
        return;
 do_sigsegv:
        force_sig(SIGSEGV, current);
+       goto out;
 }
 
 struct rt_signal_frame {
@@ -528,11 +535,13 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0)
 
 void do_notify_resume(struct pt_regs *regs, unsigned long orig_i0, unsigned long thread_info_flags)
 {
+       user_exit();
        if (thread_info_flags & _TIF_SIGPENDING)
                do_signal(regs, orig_i0);
        if (thread_info_flags & _TIF_NOTIFY_RESUME) {
                clear_thread_flag(TIF_NOTIFY_RESUME);
                tracehook_notify_resume(regs);
        }
+       user_enter();
 }
 
index d05eb9c1d8465e77fe2c4667e9827dd19842c6e5..beb0b5a5f21ff0cfaf77a48e221932d7a4b060f2 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/personality.h>
 #include <linux/random.h>
 #include <linux/export.h>
+#include <linux/context_tracking.h>
 
 #include <asm/uaccess.h>
 #include <asm/utrap.h>
@@ -496,6 +497,7 @@ asmlinkage unsigned long c_sys_nis_syscall(struct pt_regs *regs)
 
 asmlinkage void sparc_breakpoint(struct pt_regs *regs)
 {
+       enum ctx_state prev_state = exception_enter();
        siginfo_t info;
 
        if (test_thread_flag(TIF_32BIT)) {
@@ -514,6 +516,7 @@ asmlinkage void sparc_breakpoint(struct pt_regs *regs)
 #ifdef DEBUG_SPARC_BREAKPOINT
        printk ("TRAP: Returning to space: PC=%lx nPC=%lx\n", regs->tpc, regs->tnpc);
 #endif
+       exception_exit(prev_state);
 }
 
 extern void check_pending(int signum);
index d950197a17e16229d0b62147b5956924d656baf4..87729fff13b96729cd6cadcc3825dba172ab1d7c 100644 (file)
@@ -52,7 +52,7 @@ sys32_rt_sigreturn:
 #endif
        .align  32
 1:     ldx     [%g6 + TI_FLAGS], %l5
-       andcc   %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %g0
+       andcc   %l5, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0
        be,pt   %icc, rtrap
         nop
        call    syscall_trace_leave
@@ -184,7 +184,7 @@ linux_sparc_syscall32:
 
        srl     %i3, 0, %o3                             ! IEU0
        srl     %i2, 0, %o2                             ! IEU0  Group
-       andcc   %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %g0
+       andcc   %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0
        bne,pn  %icc, linux_syscall_trace32             ! CTI
         mov    %i0, %l5                                ! IEU1
 5:     call    %l7                                     ! CTI   Group brk forced
@@ -207,7 +207,7 @@ linux_sparc_syscall:
 
        mov     %i3, %o3                                ! IEU1
        mov     %i4, %o4                                ! IEU0  Group
-       andcc   %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %g0
+       andcc   %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0
        bne,pn  %icc, linux_syscall_trace               ! CTI   Group
         mov    %i0, %l5                                ! IEU0
 2:     call    %l7                                     ! CTI   Group brk forced
@@ -223,7 +223,7 @@ ret_sys_call:
 
        cmp     %o0, -ERESTART_RESTARTBLOCK
        bgeu,pn %xcc, 1f
-        andcc  %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT), %g0
+        andcc  %l0, (_TIF_SYSCALL_TRACE|_TIF_SECCOMP|_TIF_SYSCALL_AUDIT|_TIF_SYSCALL_TRACEPOINT|_TIF_NOHZ), %g0
        ldx     [%sp + PTREGS_OFF + PT_V9_TNPC], %l1 ! pc = npc
 
 2:
index b3f833ab90ebf0c95d5af6e216e58c06abc9c6a5..4ced92f05358ef942bbdb5cefed92e44d131ab3a 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/ftrace.h>
 #include <linux/reboot.h>
 #include <linux/gfp.h>
+#include <linux/context_tracking.h>
 
 #include <asm/smp.h>
 #include <asm/delay.h>
@@ -186,11 +187,12 @@ EXPORT_SYMBOL_GPL(unregister_dimm_printer);
 
 void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
+       enum ctx_state prev_state = exception_enter();
        siginfo_t info;
 
        if (notify_die(DIE_TRAP, "instruction access exception", regs,
                       0, 0x8, SIGTRAP) == NOTIFY_STOP)
-               return;
+               goto out;
 
        if (regs->tstate & TSTATE_PRIV) {
                printk("spitfire_insn_access_exception: SFSR[%016lx] "
@@ -207,6 +209,8 @@ void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, un
        info.si_addr = (void __user *)regs->tpc;
        info.si_trapno = 0;
        force_sig_info(SIGSEGV, &info, current);
+out:
+       exception_exit(prev_state);
 }
 
 void spitfire_insn_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
@@ -260,11 +264,12 @@ void sun4v_insn_access_exception_tl1(struct pt_regs *regs, unsigned long addr, u
 
 void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
+       enum ctx_state prev_state = exception_enter();
        siginfo_t info;
 
        if (notify_die(DIE_TRAP, "data access exception", regs,
                       0, 0x30, SIGTRAP) == NOTIFY_STOP)
-               return;
+               goto out;
 
        if (regs->tstate & TSTATE_PRIV) {
                /* Test if this comes from uaccess places. */
@@ -280,7 +285,7 @@ void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, un
 #endif
                        regs->tpc = entry->fixup;
                        regs->tnpc = regs->tpc + 4;
-                       return;
+                       goto out;
                }
                /* Shit... */
                printk("spitfire_data_access_exception: SFSR[%016lx] "
@@ -294,6 +299,8 @@ void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, un
        info.si_addr = (void __user *)sfar;
        info.si_trapno = 0;
        force_sig_info(SIGSEGV, &info, current);
+out:
+       exception_exit(prev_state);
 }
 
 void spitfire_data_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
@@ -1994,6 +2001,7 @@ static void sun4v_log_error(struct pt_regs *regs, struct sun4v_error_entry *ent,
  */
 void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
 {
+       enum ctx_state prev_state = exception_enter();
        struct sun4v_error_entry *ent, local_copy;
        struct trap_per_cpu *tb;
        unsigned long paddr;
@@ -2022,12 +2030,14 @@ void sun4v_resum_error(struct pt_regs *regs, unsigned long offset)
                pr_info("Shutdown request, %u seconds...\n",
                        local_copy.err_secs);
                orderly_poweroff(true);
-               return;
+               goto out;
        }
 
        sun4v_log_error(regs, &local_copy, cpu,
                        KERN_ERR "RESUMABLE ERROR",
                        &sun4v_resum_oflow_cnt);
+out:
+       exception_exit(prev_state);
 }
 
 /* If we try to printk() we'll probably make matters worse, by trying
@@ -2152,7 +2162,7 @@ void hypervisor_tlbop_error_xcall(unsigned long err, unsigned long op)
               err, op);
 }
 
-void do_fpe_common(struct pt_regs *regs)
+static void do_fpe_common(struct pt_regs *regs)
 {
        if (regs->tstate & TSTATE_PRIV) {
                regs->tpc = regs->tnpc;
@@ -2188,23 +2198,28 @@ void do_fpe_common(struct pt_regs *regs)
 
 void do_fpieee(struct pt_regs *regs)
 {
+       enum ctx_state prev_state = exception_enter();
+
        if (notify_die(DIE_TRAP, "fpu exception ieee", regs,
                       0, 0x24, SIGFPE) == NOTIFY_STOP)
-               return;
+               goto out;
 
        do_fpe_common(regs);
+out:
+       exception_exit(prev_state);
 }
 
 extern int do_mathemu(struct pt_regs *, struct fpustate *, bool);
 
 void do_fpother(struct pt_regs *regs)
 {
+       enum ctx_state prev_state = exception_enter();
        struct fpustate *f = FPUSTATE;
        int ret = 0;
 
        if (notify_die(DIE_TRAP, "fpu exception other", regs,
                       0, 0x25, SIGFPE) == NOTIFY_STOP)
-               return;
+               goto out;
 
        switch ((current_thread_info()->xfsr[0] & 0x1c000)) {
        case (2 << 14): /* unfinished_FPop */
@@ -2213,17 +2228,20 @@ void do_fpother(struct pt_regs *regs)
                break;
        }
        if (ret)
-               return;
+               goto out;
        do_fpe_common(regs);
+out:
+       exception_exit(prev_state);
 }
 
 void do_tof(struct pt_regs *regs)
 {
+       enum ctx_state prev_state = exception_enter();
        siginfo_t info;
 
        if (notify_die(DIE_TRAP, "tagged arithmetic overflow", regs,
                       0, 0x26, SIGEMT) == NOTIFY_STOP)
-               return;
+               goto out;
 
        if (regs->tstate & TSTATE_PRIV)
                die_if_kernel("Penguin overflow trap from kernel mode", regs);
@@ -2237,15 +2255,18 @@ void do_tof(struct pt_regs *regs)
        info.si_addr = (void __user *)regs->tpc;
        info.si_trapno = 0;
        force_sig_info(SIGEMT, &info, current);
+out:
+       exception_exit(prev_state);
 }
 
 void do_div0(struct pt_regs *regs)
 {
+       enum ctx_state prev_state = exception_enter();
        siginfo_t info;
 
        if (notify_die(DIE_TRAP, "integer division by zero", regs,
                       0, 0x28, SIGFPE) == NOTIFY_STOP)
-               return;
+               goto out;
 
        if (regs->tstate & TSTATE_PRIV)
                die_if_kernel("TL0: Kernel divide by zero.", regs);
@@ -2259,6 +2280,8 @@ void do_div0(struct pt_regs *regs)
        info.si_addr = (void __user *)regs->tpc;
        info.si_trapno = 0;
        force_sig_info(SIGFPE, &info, current);
+out:
+       exception_exit(prev_state);
 }
 
 static void instruction_dump(unsigned int *pc)
@@ -2415,6 +2438,7 @@ extern int handle_ldf_stq(u32 insn, struct pt_regs *regs);
 
 void do_illegal_instruction(struct pt_regs *regs)
 {
+       enum ctx_state prev_state = exception_enter();
        unsigned long pc = regs->tpc;
        unsigned long tstate = regs->tstate;
        u32 insn;
@@ -2422,7 +2446,7 @@ void do_illegal_instruction(struct pt_regs *regs)
 
        if (notify_die(DIE_TRAP, "illegal instruction", regs,
                       0, 0x10, SIGILL) == NOTIFY_STOP)
-               return;
+               goto out;
 
        if (tstate & TSTATE_PRIV)
                die_if_kernel("Kernel illegal instruction", regs);
@@ -2431,14 +2455,14 @@ void do_illegal_instruction(struct pt_regs *regs)
        if (get_user(insn, (u32 __user *) pc) != -EFAULT) {
                if ((insn & 0xc1ffc000) == 0x81700000) /* POPC */ {
                        if (handle_popc(insn, regs))
-                               return;
+                               goto out;
                } else if ((insn & 0xc1580000) == 0xc1100000) /* LDQ/STQ */ {
                        if (handle_ldf_stq(insn, regs))
-                               return;
+                               goto out;
                } else if (tlb_type == hypervisor) {
                        if ((insn & VIS_OPCODE_MASK) == VIS_OPCODE_VAL) {
                                if (!vis_emul(regs, insn))
-                                       return;
+                                       goto out;
                        } else {
                                struct fpustate *f = FPUSTATE;
 
@@ -2448,7 +2472,7 @@ void do_illegal_instruction(struct pt_regs *regs)
                                 * Trap in the %fsr to unimplemented_FPop.
                                 */
                                if (do_mathemu(regs, f, true))
-                                       return;
+                                       goto out;
                        }
                }
        }
@@ -2458,21 +2482,24 @@ void do_illegal_instruction(struct pt_regs *regs)
        info.si_addr = (void __user *)pc;
        info.si_trapno = 0;
        force_sig_info(SIGILL, &info, current);
+out:
+       exception_exit(prev_state);
 }
 
 extern void kernel_unaligned_trap(struct pt_regs *regs, unsigned int insn);
 
 void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr)
 {
+       enum ctx_state prev_state = exception_enter();
        siginfo_t info;
 
        if (notify_die(DIE_TRAP, "memory address unaligned", regs,
                       0, 0x34, SIGSEGV) == NOTIFY_STOP)
-               return;
+               goto out;
 
        if (regs->tstate & TSTATE_PRIV) {
                kernel_unaligned_trap(regs, *((unsigned int *)regs->tpc));
-               return;
+               goto out;
        }
        info.si_signo = SIGBUS;
        info.si_errno = 0;
@@ -2480,6 +2507,8 @@ void mem_address_unaligned(struct pt_regs *regs, unsigned long sfar, unsigned lo
        info.si_addr = (void __user *)sfar;
        info.si_trapno = 0;
        force_sig_info(SIGBUS, &info, current);
+out:
+       exception_exit(prev_state);
 }
 
 void sun4v_do_mna(struct pt_regs *regs, unsigned long addr, unsigned long type_ctx)
@@ -2504,11 +2533,12 @@ void sun4v_do_mna(struct pt_regs *regs, unsigned long addr, unsigned long type_c
 
 void do_privop(struct pt_regs *regs)
 {
+       enum ctx_state prev_state = exception_enter();
        siginfo_t info;
 
        if (notify_die(DIE_TRAP, "privileged operation", regs,
                       0, 0x11, SIGILL) == NOTIFY_STOP)
-               return;
+               goto out;
 
        if (test_thread_flag(TIF_32BIT)) {
                regs->tpc &= 0xffffffff;
@@ -2520,6 +2550,8 @@ void do_privop(struct pt_regs *regs)
        info.si_addr = (void __user *)regs->tpc;
        info.si_trapno = 0;
        force_sig_info(SIGILL, &info, current);
+out:
+       exception_exit(prev_state);
 }
 
 void do_privact(struct pt_regs *regs)
@@ -2530,99 +2562,116 @@ void do_privact(struct pt_regs *regs)
 /* Trap level 1 stuff or other traps we should never see... */
 void do_cee(struct pt_regs *regs)
 {
+       exception_enter();
        die_if_kernel("TL0: Cache Error Exception", regs);
 }
 
 void do_cee_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: Cache Error Exception", regs);
 }
 
 void do_dae_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: Data Access Exception", regs);
 }
 
 void do_iae_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: Instruction Access Exception", regs);
 }
 
 void do_div0_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: DIV0 Exception", regs);
 }
 
 void do_fpdis_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: FPU Disabled", regs);
 }
 
 void do_fpieee_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: FPU IEEE Exception", regs);
 }
 
 void do_fpother_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: FPU Other Exception", regs);
 }
 
 void do_ill_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: Illegal Instruction Exception", regs);
 }
 
 void do_irq_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: IRQ Exception", regs);
 }
 
 void do_lddfmna_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: LDDF Exception", regs);
 }
 
 void do_stdfmna_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: STDF Exception", regs);
 }
 
 void do_paw(struct pt_regs *regs)
 {
+       exception_enter();
        die_if_kernel("TL0: Phys Watchpoint Exception", regs);
 }
 
 void do_paw_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: Phys Watchpoint Exception", regs);
 }
 
 void do_vaw(struct pt_regs *regs)
 {
+       exception_enter();
        die_if_kernel("TL0: Virt Watchpoint Exception", regs);
 }
 
 void do_vaw_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: Virt Watchpoint Exception", regs);
 }
 
 void do_tof_tl1(struct pt_regs *regs)
 {
+       exception_enter();
        dump_tl1_traplog((struct tl1_traplog *)(regs + 1));
        die_if_kernel("TL1: Tag Overflow Exception", regs);
 }
index 8201c25e76697ad5f5a96de1b6921a3fb34372ac..3c1a7cb31579fd0fe55e68bced2dc11757734c35 100644 (file)
 #include <linux/bitops.h>
 #include <linux/perf_event.h>
 #include <linux/ratelimit.h>
+#include <linux/context_tracking.h>
 #include <asm/fpumacro.h>
 #include <asm/cacheflush.h>
 
+#include "entry.h"
+
 enum direction {
        load,    /* ld, ldd, ldh, ldsh */
        store,   /* st, std, sth, stsh */
@@ -418,9 +421,6 @@ int handle_popc(u32 insn, struct pt_regs *regs)
 
 extern void do_fpother(struct pt_regs *regs);
 extern void do_privact(struct pt_regs *regs);
-extern void spitfire_data_access_exception(struct pt_regs *regs,
-                                          unsigned long sfsr,
-                                          unsigned long sfar);
 extern void sun4v_data_access_exception(struct pt_regs *regs,
                                        unsigned long addr,
                                        unsigned long type_ctx);
@@ -578,6 +578,7 @@ void handle_ld_nf(u32 insn, struct pt_regs *regs)
 
 void handle_lddfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr)
 {
+       enum ctx_state prev_state = exception_enter();
        unsigned long pc = regs->tpc;
        unsigned long tstate = regs->tstate;
        u32 insn;
@@ -632,13 +633,16 @@ daex:
                        sun4v_data_access_exception(regs, sfar, sfsr);
                else
                        spitfire_data_access_exception(regs, sfsr, sfar);
-               return;
+               goto out;
        }
        advance(regs);
+out:
+       exception_exit(prev_state);
 }
 
 void handle_stdfmna(struct pt_regs *regs, unsigned long sfar, unsigned long sfsr)
 {
+       enum ctx_state prev_state = exception_enter();
        unsigned long pc = regs->tpc;
        unsigned long tstate = regs->tstate;
        u32 insn;
@@ -680,7 +684,9 @@ daex:
                        sun4v_data_access_exception(regs, sfar, sfsr);
                else
                        spitfire_data_access_exception(regs, sfsr, sfar);
-               return;
+               goto out;
        }
        advance(regs);
+out:
+       exception_exit(prev_state);
 }
index 2ebec263d6859f317041d75d0172abde1fd4e4d5..69bb818fdd798b8d50dff44a46a9941272972a92 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/kprobes.h>
 #include <linux/kdebug.h>
 #include <linux/percpu.h>
+#include <linux/context_tracking.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -272,6 +273,7 @@ static void noinline __kprobes bogus_32bit_fault_address(struct pt_regs *regs,
 
 asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
 {
+       enum ctx_state prev_state = exception_enter();
        struct mm_struct *mm = current->mm;
        struct vm_area_struct *vma;
        unsigned int insn = 0;
@@ -282,7 +284,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
        fault_code = get_thread_fault_code();
 
        if (notify_page_fault(regs))
-               return;
+               goto exit_exception;
 
        si_code = SEGV_MAPERR;
        address = current_thread_info()->fault_address;
@@ -313,7 +315,7 @@ asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs)
                        /* Valid, no problems... */
                } else {
                        bad_kernel_pc(regs, address);
-                       return;
+                       goto exit_exception;
                }
        } else
                flags |= FAULT_FLAG_USER;
@@ -430,7 +432,7 @@ good_area:
        fault = handle_mm_fault(mm, vma, address, flags);
 
        if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
-               return;
+               goto exit_exception;
 
        if (unlikely(fault & VM_FAULT_ERROR)) {
                if (fault & VM_FAULT_OOM)
@@ -482,6 +484,8 @@ good_area:
 
        }
 #endif
+exit_exception:
+       exception_exit(prev_state);
        return;
 
        /*
@@ -494,7 +498,7 @@ bad_area:
 
 handle_kernel_fault:
        do_kernel_fault(regs, si_code, fault_code, insn, address);
-       return;
+       goto exit_exception;
 
 /*
  * We ran out of memory, or some other thing happened to us that made
@@ -505,7 +509,7 @@ out_of_memory:
        up_read(&mm->mmap_sem);
        if (!(regs->tstate & TSTATE_PRIV)) {
                pagefault_out_of_memory();
-               return;
+               goto exit_exception;
        }
        goto handle_kernel_fault;