aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/Kconfig1
-rw-r--r--arch/x86/include/asm/rcu.h32
-rw-r--r--arch/x86/include/asm/thread_info.h10
-rw-r--r--arch/x86/kernel/cpuid.c5
-rw-r--r--arch/x86/kernel/entry_64.S9
-rw-r--r--arch/x86/kernel/msr.c5
-rw-r--r--arch/x86/kernel/ptrace.c5
-rw-r--r--arch/x86/kernel/signal.c4
-rw-r--r--arch/x86/kernel/traps.c109
-rw-r--r--arch/x86/mm/fault.c13
10 files changed, 141 insertions, 52 deletions
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 50a1d1f9b6d3..20c49b8450b8 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -97,6 +97,7 @@ config X86
97 select KTIME_SCALAR if X86_32 97 select KTIME_SCALAR if X86_32
98 select GENERIC_STRNCPY_FROM_USER 98 select GENERIC_STRNCPY_FROM_USER
99 select GENERIC_STRNLEN_USER 99 select GENERIC_STRNLEN_USER
100 select HAVE_RCU_USER_QS if X86_64
100 101
101config INSTRUCTION_DECODER 102config INSTRUCTION_DECODER
102 def_bool (KPROBES || PERF_EVENTS || UPROBES) 103 def_bool (KPROBES || PERF_EVENTS || UPROBES)
diff --git a/arch/x86/include/asm/rcu.h b/arch/x86/include/asm/rcu.h
new file mode 100644
index 000000000000..d1ac07a23979
--- /dev/null
+++ b/arch/x86/include/asm/rcu.h
@@ -0,0 +1,32 @@
1#ifndef _ASM_X86_RCU_H
2#define _ASM_X86_RCU_H
3
4#ifndef __ASSEMBLY__
5
6#include <linux/rcupdate.h>
7#include <asm/ptrace.h>
8
9static inline void exception_enter(struct pt_regs *regs)
10{
11 rcu_user_exit();
12}
13
14static inline void exception_exit(struct pt_regs *regs)
15{
16#ifdef CONFIG_RCU_USER_QS
17 if (user_mode(regs))
18 rcu_user_enter();
19#endif
20}
21
22#else /* __ASSEMBLY__ */
23
24#ifdef CONFIG_RCU_USER_QS
25# define SCHEDULE_USER call schedule_user
26#else
27# define SCHEDULE_USER call schedule
28#endif
29
30#endif /* !__ASSEMBLY__ */
31
32#endif
diff --git a/arch/x86/include/asm/thread_info.h b/arch/x86/include/asm/thread_info.h
index 89f794f007ec..c535d847e3b5 100644
--- a/arch/x86/include/asm/thread_info.h
+++ b/arch/x86/include/asm/thread_info.h
@@ -89,6 +89,7 @@ struct thread_info {
89#define TIF_NOTSC 16 /* TSC is not accessible in userland */ 89#define TIF_NOTSC 16 /* TSC is not accessible in userland */
90#define TIF_IA32 17 /* IA32 compatibility process */ 90#define TIF_IA32 17 /* IA32 compatibility process */
91#define TIF_FORK 18 /* ret_from_fork */ 91#define TIF_FORK 18 /* ret_from_fork */
92#define TIF_NOHZ 19 /* in adaptive nohz mode */
92#define TIF_MEMDIE 20 /* is terminating due to OOM killer */ 93#define TIF_MEMDIE 20 /* is terminating due to OOM killer */
93#define TIF_DEBUG 21 /* uses debug registers */ 94#define TIF_DEBUG 21 /* uses debug registers */
94#define TIF_IO_BITMAP 22 /* uses I/O bitmap */ 95#define TIF_IO_BITMAP 22 /* uses I/O bitmap */
@@ -114,6 +115,7 @@ struct thread_info {
114#define _TIF_NOTSC (1 << TIF_NOTSC) 115#define _TIF_NOTSC (1 << TIF_NOTSC)
115#define _TIF_IA32 (1 << TIF_IA32) 116#define _TIF_IA32 (1 << TIF_IA32)
116#define _TIF_FORK (1 << TIF_FORK) 117#define _TIF_FORK (1 << TIF_FORK)
118#define _TIF_NOHZ (1 << TIF_NOHZ)
117#define _TIF_DEBUG (1 << TIF_DEBUG) 119#define _TIF_DEBUG (1 << TIF_DEBUG)
118#define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP) 120#define _TIF_IO_BITMAP (1 << TIF_IO_BITMAP)
119#define _TIF_FORCED_TF (1 << TIF_FORCED_TF) 121#define _TIF_FORCED_TF (1 << TIF_FORCED_TF)
@@ -126,12 +128,13 @@ struct thread_info {
126/* work to do in syscall_trace_enter() */ 128/* work to do in syscall_trace_enter() */
127#define _TIF_WORK_SYSCALL_ENTRY \ 129#define _TIF_WORK_SYSCALL_ENTRY \
128 (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT | \ 130 (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU | _TIF_SYSCALL_AUDIT | \
129 _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT) 131 _TIF_SECCOMP | _TIF_SINGLESTEP | _TIF_SYSCALL_TRACEPOINT | \
132 _TIF_NOHZ)
130 133
131/* work to do in syscall_trace_leave() */ 134/* work to do in syscall_trace_leave() */
132#define _TIF_WORK_SYSCALL_EXIT \ 135#define _TIF_WORK_SYSCALL_EXIT \
133 (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP | \ 136 (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SINGLESTEP | \
134 _TIF_SYSCALL_TRACEPOINT) 137 _TIF_SYSCALL_TRACEPOINT | _TIF_NOHZ)
135 138
136/* work to do on interrupt/exception return */ 139/* work to do on interrupt/exception return */
137#define _TIF_WORK_MASK \ 140#define _TIF_WORK_MASK \
@@ -141,7 +144,8 @@ struct thread_info {
141 144
142/* work to do on any return to user space */ 145/* work to do on any return to user space */
143#define _TIF_ALLWORK_MASK \ 146#define _TIF_ALLWORK_MASK \
144 ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT) 147 ((0x0000FFFF & ~_TIF_SECCOMP) | _TIF_SYSCALL_TRACEPOINT | \
148 _TIF_NOHZ)
145 149
146/* Only used for 64 bit */ 150/* Only used for 64 bit */
147#define _TIF_DO_NOTIFY_MASK \ 151#define _TIF_DO_NOTIFY_MASK \
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index 39472dd2323f..60c78917190c 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -199,12 +199,14 @@ static int __init cpuid_init(void)
199 goto out_chrdev; 199 goto out_chrdev;
200 } 200 }
201 cpuid_class->devnode = cpuid_devnode; 201 cpuid_class->devnode = cpuid_devnode;
202 get_online_cpus();
202 for_each_online_cpu(i) { 203 for_each_online_cpu(i) {
203 err = cpuid_device_create(i); 204 err = cpuid_device_create(i);
204 if (err != 0) 205 if (err != 0)
205 goto out_class; 206 goto out_class;
206 } 207 }
207 register_hotcpu_notifier(&cpuid_class_cpu_notifier); 208 register_hotcpu_notifier(&cpuid_class_cpu_notifier);
209 put_online_cpus();
208 210
209 err = 0; 211 err = 0;
210 goto out; 212 goto out;
@@ -214,6 +216,7 @@ out_class:
214 for_each_online_cpu(i) { 216 for_each_online_cpu(i) {
215 cpuid_device_destroy(i); 217 cpuid_device_destroy(i);
216 } 218 }
219 put_online_cpus();
217 class_destroy(cpuid_class); 220 class_destroy(cpuid_class);
218out_chrdev: 221out_chrdev:
219 __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid"); 222 __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
@@ -225,11 +228,13 @@ static void __exit cpuid_exit(void)
225{ 228{
226 int cpu = 0; 229 int cpu = 0;
227 230
231 get_online_cpus();
228 for_each_online_cpu(cpu) 232 for_each_online_cpu(cpu)
229 cpuid_device_destroy(cpu); 233 cpuid_device_destroy(cpu);
230 class_destroy(cpuid_class); 234 class_destroy(cpuid_class);
231 __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid"); 235 __unregister_chrdev(CPUID_MAJOR, 0, NR_CPUS, "cpu/cpuid");
232 unregister_hotcpu_notifier(&cpuid_class_cpu_notifier); 236 unregister_hotcpu_notifier(&cpuid_class_cpu_notifier);
237 put_online_cpus();
233} 238}
234 239
235module_init(cpuid_init); 240module_init(cpuid_init);
diff --git a/arch/x86/kernel/entry_64.S b/arch/x86/kernel/entry_64.S
index 69babd8c834f..1a8f3cbb6ee3 100644
--- a/arch/x86/kernel/entry_64.S
+++ b/arch/x86/kernel/entry_64.S
@@ -56,6 +56,7 @@
56#include <asm/ftrace.h> 56#include <asm/ftrace.h>
57#include <asm/percpu.h> 57#include <asm/percpu.h>
58#include <asm/asm.h> 58#include <asm/asm.h>
59#include <asm/rcu.h>
59#include <linux/err.h> 60#include <linux/err.h>
60 61
61/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */ 62/* Avoid __ASSEMBLER__'ifying <linux/audit.h> just for this. */
@@ -565,7 +566,7 @@ sysret_careful:
565 TRACE_IRQS_ON 566 TRACE_IRQS_ON
566 ENABLE_INTERRUPTS(CLBR_NONE) 567 ENABLE_INTERRUPTS(CLBR_NONE)
567 pushq_cfi %rdi 568 pushq_cfi %rdi
568 call schedule 569 SCHEDULE_USER
569 popq_cfi %rdi 570 popq_cfi %rdi
570 jmp sysret_check 571 jmp sysret_check
571 572
@@ -678,7 +679,7 @@ int_careful:
678 TRACE_IRQS_ON 679 TRACE_IRQS_ON
679 ENABLE_INTERRUPTS(CLBR_NONE) 680 ENABLE_INTERRUPTS(CLBR_NONE)
680 pushq_cfi %rdi 681 pushq_cfi %rdi
681 call schedule 682 SCHEDULE_USER
682 popq_cfi %rdi 683 popq_cfi %rdi
683 DISABLE_INTERRUPTS(CLBR_NONE) 684 DISABLE_INTERRUPTS(CLBR_NONE)
684 TRACE_IRQS_OFF 685 TRACE_IRQS_OFF
@@ -974,7 +975,7 @@ retint_careful:
974 TRACE_IRQS_ON 975 TRACE_IRQS_ON
975 ENABLE_INTERRUPTS(CLBR_NONE) 976 ENABLE_INTERRUPTS(CLBR_NONE)
976 pushq_cfi %rdi 977 pushq_cfi %rdi
977 call schedule 978 SCHEDULE_USER
978 popq_cfi %rdi 979 popq_cfi %rdi
979 GET_THREAD_INFO(%rcx) 980 GET_THREAD_INFO(%rcx)
980 DISABLE_INTERRUPTS(CLBR_NONE) 981 DISABLE_INTERRUPTS(CLBR_NONE)
@@ -1449,7 +1450,7 @@ paranoid_userspace:
1449paranoid_schedule: 1450paranoid_schedule:
1450 TRACE_IRQS_ON 1451 TRACE_IRQS_ON
1451 ENABLE_INTERRUPTS(CLBR_ANY) 1452 ENABLE_INTERRUPTS(CLBR_ANY)
1452 call schedule 1453 SCHEDULE_USER
1453 DISABLE_INTERRUPTS(CLBR_ANY) 1454 DISABLE_INTERRUPTS(CLBR_ANY)
1454 TRACE_IRQS_OFF 1455 TRACE_IRQS_OFF
1455 jmp paranoid_userspace 1456 jmp paranoid_userspace
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index eb113693f043..a7c5661f8496 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -257,12 +257,14 @@ static int __init msr_init(void)
257 goto out_chrdev; 257 goto out_chrdev;
258 } 258 }
259 msr_class->devnode = msr_devnode; 259 msr_class->devnode = msr_devnode;
260 get_online_cpus();
260 for_each_online_cpu(i) { 261 for_each_online_cpu(i) {
261 err = msr_device_create(i); 262 err = msr_device_create(i);
262 if (err != 0) 263 if (err != 0)
263 goto out_class; 264 goto out_class;
264 } 265 }
265 register_hotcpu_notifier(&msr_class_cpu_notifier); 266 register_hotcpu_notifier(&msr_class_cpu_notifier);
267 put_online_cpus();
266 268
267 err = 0; 269 err = 0;
268 goto out; 270 goto out;
@@ -271,6 +273,7 @@ out_class:
271 i = 0; 273 i = 0;
272 for_each_online_cpu(i) 274 for_each_online_cpu(i)
273 msr_device_destroy(i); 275 msr_device_destroy(i);
276 put_online_cpus();
274 class_destroy(msr_class); 277 class_destroy(msr_class);
275out_chrdev: 278out_chrdev:
276 __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr"); 279 __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
@@ -281,11 +284,13 @@ out:
281static void __exit msr_exit(void) 284static void __exit msr_exit(void)
282{ 285{
283 int cpu = 0; 286 int cpu = 0;
287 get_online_cpus();
284 for_each_online_cpu(cpu) 288 for_each_online_cpu(cpu)
285 msr_device_destroy(cpu); 289 msr_device_destroy(cpu);
286 class_destroy(msr_class); 290 class_destroy(msr_class);
287 __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr"); 291 __unregister_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr");
288 unregister_hotcpu_notifier(&msr_class_cpu_notifier); 292 unregister_hotcpu_notifier(&msr_class_cpu_notifier);
293 put_online_cpus();
289} 294}
290 295
291module_init(msr_init); 296module_init(msr_init);
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index c4c6a5c2bf0f..9f94f8ec26e4 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -21,6 +21,7 @@
21#include <linux/signal.h> 21#include <linux/signal.h>
22#include <linux/perf_event.h> 22#include <linux/perf_event.h>
23#include <linux/hw_breakpoint.h> 23#include <linux/hw_breakpoint.h>
24#include <linux/rcupdate.h>
24 25
25#include <asm/uaccess.h> 26#include <asm/uaccess.h>
26#include <asm/pgtable.h> 27#include <asm/pgtable.h>
@@ -1463,6 +1464,8 @@ long syscall_trace_enter(struct pt_regs *regs)
1463{ 1464{
1464 long ret = 0; 1465 long ret = 0;
1465 1466
1467 rcu_user_exit();
1468
1466 /* 1469 /*
1467 * If we stepped into a sysenter/syscall insn, it trapped in 1470 * If we stepped into a sysenter/syscall insn, it trapped in
1468 * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP. 1471 * kernel mode; do_debug() cleared TF and set TIF_SINGLESTEP.
@@ -1526,4 +1529,6 @@ void syscall_trace_leave(struct pt_regs *regs)
1526 !test_thread_flag(TIF_SYSCALL_EMU); 1529 !test_thread_flag(TIF_SYSCALL_EMU);
1527 if (step || test_thread_flag(TIF_SYSCALL_TRACE)) 1530 if (step || test_thread_flag(TIF_SYSCALL_TRACE))
1528 tracehook_report_syscall_exit(regs, step); 1531 tracehook_report_syscall_exit(regs, step);
1532
1533 rcu_user_enter();
1529} 1534}
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c
index b280908a376e..bca0ab903e57 100644
--- a/arch/x86/kernel/signal.c
+++ b/arch/x86/kernel/signal.c
@@ -779,6 +779,8 @@ static void do_signal(struct pt_regs *regs)
779void 779void
780do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags) 780do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
781{ 781{
782 rcu_user_exit();
783
782#ifdef CONFIG_X86_MCE 784#ifdef CONFIG_X86_MCE
783 /* notify userspace of pending MCEs */ 785 /* notify userspace of pending MCEs */
784 if (thread_info_flags & _TIF_MCE_NOTIFY) 786 if (thread_info_flags & _TIF_MCE_NOTIFY)
@@ -804,6 +806,8 @@ do_notify_resume(struct pt_regs *regs, void *unused, __u32 thread_info_flags)
804#ifdef CONFIG_X86_32 806#ifdef CONFIG_X86_32
805 clear_thread_flag(TIF_IRET); 807 clear_thread_flag(TIF_IRET);
806#endif /* CONFIG_X86_32 */ 808#endif /* CONFIG_X86_32 */
809
810 rcu_user_enter();
807} 811}
808 812
809void signal_fault(struct pt_regs *regs, void __user *frame, char *where) 813void signal_fault(struct pt_regs *regs, void __user *frame, char *where)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index b481341c9369..378967578f22 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -55,6 +55,7 @@
55#include <asm/i387.h> 55#include <asm/i387.h>
56#include <asm/fpu-internal.h> 56#include <asm/fpu-internal.h>
57#include <asm/mce.h> 57#include <asm/mce.h>
58#include <asm/rcu.h>
58 59
59#include <asm/mach_traps.h> 60#include <asm/mach_traps.h>
60 61
@@ -180,11 +181,15 @@ vm86_trap:
180#define DO_ERROR(trapnr, signr, str, name) \ 181#define DO_ERROR(trapnr, signr, str, name) \
181dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ 182dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
182{ \ 183{ \
183 if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ 184 exception_enter(regs); \
184 == NOTIFY_STOP) \ 185 if (notify_die(DIE_TRAP, str, regs, error_code, \
186 trapnr, signr) == NOTIFY_STOP) { \
187 exception_exit(regs); \
185 return; \ 188 return; \
189 } \
186 conditional_sti(regs); \ 190 conditional_sti(regs); \
187 do_trap(trapnr, signr, str, regs, error_code, NULL); \ 191 do_trap(trapnr, signr, str, regs, error_code, NULL); \
192 exception_exit(regs); \
188} 193}
189 194
190#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ 195#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
@@ -195,11 +200,15 @@ dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
195 info.si_errno = 0; \ 200 info.si_errno = 0; \
196 info.si_code = sicode; \ 201 info.si_code = sicode; \
197 info.si_addr = (void __user *)siaddr; \ 202 info.si_addr = (void __user *)siaddr; \
198 if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ 203 exception_enter(regs); \
199 == NOTIFY_STOP) \ 204 if (notify_die(DIE_TRAP, str, regs, error_code, \
205 trapnr, signr) == NOTIFY_STOP) { \
206 exception_exit(regs); \
200 return; \ 207 return; \
208 } \
201 conditional_sti(regs); \ 209 conditional_sti(regs); \
202 do_trap(trapnr, signr, str, regs, error_code, &info); \ 210 do_trap(trapnr, signr, str, regs, error_code, &info); \
211 exception_exit(regs); \
203} 212}
204 213
205DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV, 214DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
@@ -222,12 +231,14 @@ DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check,
222/* Runs on IST stack */ 231/* Runs on IST stack */
223dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) 232dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
224{ 233{
234 exception_enter(regs);
225 if (notify_die(DIE_TRAP, "stack segment", regs, error_code, 235 if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
226 X86_TRAP_SS, SIGBUS) == NOTIFY_STOP) 236 X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
227 return; 237 preempt_conditional_sti(regs);
228 preempt_conditional_sti(regs); 238 do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
229 do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); 239 preempt_conditional_cli(regs);
230 preempt_conditional_cli(regs); 240 }
241 exception_exit(regs);
231} 242}
232 243
233dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) 244dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
@@ -235,6 +246,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
235 static const char str[] = "double fault"; 246 static const char str[] = "double fault";
236 struct task_struct *tsk = current; 247 struct task_struct *tsk = current;
237 248
249 exception_enter(regs);
238 /* Return not checked because double check cannot be ignored */ 250 /* Return not checked because double check cannot be ignored */
239 notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV); 251 notify_die(DIE_TRAP, str, regs, error_code, X86_TRAP_DF, SIGSEGV);
240 252
@@ -255,16 +267,29 @@ do_general_protection(struct pt_regs *regs, long error_code)
255{ 267{
256 struct task_struct *tsk; 268 struct task_struct *tsk;
257 269
270 exception_enter(regs);
258 conditional_sti(regs); 271 conditional_sti(regs);
259 272
260#ifdef CONFIG_X86_32 273#ifdef CONFIG_X86_32
261 if (regs->flags & X86_VM_MASK) 274 if (regs->flags & X86_VM_MASK) {
262 goto gp_in_vm86; 275 local_irq_enable();
276 handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
277 goto exit;
278 }
263#endif 279#endif
264 280
265 tsk = current; 281 tsk = current;
266 if (!user_mode(regs)) 282 if (!user_mode(regs)) {
267 goto gp_in_kernel; 283 if (fixup_exception(regs))
284 goto exit;
285
286 tsk->thread.error_code = error_code;
287 tsk->thread.trap_nr = X86_TRAP_GP;
288 if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
289 X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP)
290 die("general protection fault", regs, error_code);
291 goto exit;
292 }
268 293
269 tsk->thread.error_code = error_code; 294 tsk->thread.error_code = error_code;
270 tsk->thread.trap_nr = X86_TRAP_GP; 295 tsk->thread.trap_nr = X86_TRAP_GP;
@@ -279,25 +304,8 @@ do_general_protection(struct pt_regs *regs, long error_code)
279 } 304 }
280 305
281 force_sig(SIGSEGV, tsk); 306 force_sig(SIGSEGV, tsk);
282 return; 307exit:
283 308 exception_exit(regs);
284#ifdef CONFIG_X86_32
285gp_in_vm86:
286 local_irq_enable();
287 handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
288 return;
289#endif
290
291gp_in_kernel:
292 if (fixup_exception(regs))
293 return;
294
295 tsk->thread.error_code = error_code;
296 tsk->thread.trap_nr = X86_TRAP_GP;
297 if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
298 X86_TRAP_GP, SIGSEGV) == NOTIFY_STOP)
299 return;
300 die("general protection fault", regs, error_code);
301} 309}
302 310
303/* May run on IST stack. */ 311/* May run on IST stack. */
@@ -312,15 +320,16 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
312 ftrace_int3_handler(regs)) 320 ftrace_int3_handler(regs))
313 return; 321 return;
314#endif 322#endif
323 exception_enter(regs);
315#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP 324#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
316 if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, 325 if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
317 SIGTRAP) == NOTIFY_STOP) 326 SIGTRAP) == NOTIFY_STOP)
318 return; 327 goto exit;
319#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ 328#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
320 329
321 if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, 330 if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
322 SIGTRAP) == NOTIFY_STOP) 331 SIGTRAP) == NOTIFY_STOP)
323 return; 332 goto exit;
324 333
325 /* 334 /*
326 * Let others (NMI) know that the debug stack is in use 335 * Let others (NMI) know that the debug stack is in use
@@ -331,6 +340,8 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
331 do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL); 340 do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
332 preempt_conditional_cli(regs); 341 preempt_conditional_cli(regs);
333 debug_stack_usage_dec(); 342 debug_stack_usage_dec();
343exit:
344 exception_exit(regs);
334} 345}
335 346
336#ifdef CONFIG_X86_64 347#ifdef CONFIG_X86_64
@@ -391,6 +402,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
391 unsigned long dr6; 402 unsigned long dr6;
392 int si_code; 403 int si_code;
393 404
405 exception_enter(regs);
406
394 get_debugreg(dr6, 6); 407 get_debugreg(dr6, 6);
395 408
396 /* Filter out all the reserved bits which are preset to 1 */ 409 /* Filter out all the reserved bits which are preset to 1 */
@@ -406,7 +419,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
406 419
407 /* Catch kmemcheck conditions first of all! */ 420 /* Catch kmemcheck conditions first of all! */
408 if ((dr6 & DR_STEP) && kmemcheck_trap(regs)) 421 if ((dr6 & DR_STEP) && kmemcheck_trap(regs))
409 return; 422 goto exit;
410 423
411 /* DR6 may or may not be cleared by the CPU */ 424 /* DR6 may or may not be cleared by the CPU */
412 set_debugreg(0, 6); 425 set_debugreg(0, 6);
@@ -421,7 +434,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
421 434
422 if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code, 435 if (notify_die(DIE_DEBUG, "debug", regs, PTR_ERR(&dr6), error_code,
423 SIGTRAP) == NOTIFY_STOP) 436 SIGTRAP) == NOTIFY_STOP)
424 return; 437 goto exit;
425 438
426 /* 439 /*
427 * Let others (NMI) know that the debug stack is in use 440 * Let others (NMI) know that the debug stack is in use
@@ -437,7 +450,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
437 X86_TRAP_DB); 450 X86_TRAP_DB);
438 preempt_conditional_cli(regs); 451 preempt_conditional_cli(regs);
439 debug_stack_usage_dec(); 452 debug_stack_usage_dec();
440 return; 453 goto exit;
441 } 454 }
442 455
443 /* 456 /*
@@ -458,7 +471,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
458 preempt_conditional_cli(regs); 471 preempt_conditional_cli(regs);
459 debug_stack_usage_dec(); 472 debug_stack_usage_dec();
460 473
461 return; 474exit:
475 exception_exit(regs);
462} 476}
463 477
464/* 478/*
@@ -555,14 +569,17 @@ dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
555#ifdef CONFIG_X86_32 569#ifdef CONFIG_X86_32
556 ignore_fpu_irq = 1; 570 ignore_fpu_irq = 1;
557#endif 571#endif
558 572 exception_enter(regs);
559 math_error(regs, error_code, X86_TRAP_MF); 573 math_error(regs, error_code, X86_TRAP_MF);
574 exception_exit(regs);
560} 575}
561 576
562dotraplinkage void 577dotraplinkage void
563do_simd_coprocessor_error(struct pt_regs *regs, long error_code) 578do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
564{ 579{
580 exception_enter(regs);
565 math_error(regs, error_code, X86_TRAP_XF); 581 math_error(regs, error_code, X86_TRAP_XF);
582 exception_exit(regs);
566} 583}
567 584
568dotraplinkage void 585dotraplinkage void
@@ -629,6 +646,7 @@ EXPORT_SYMBOL_GPL(math_state_restore);
629dotraplinkage void __kprobes 646dotraplinkage void __kprobes
630do_device_not_available(struct pt_regs *regs, long error_code) 647do_device_not_available(struct pt_regs *regs, long error_code)
631{ 648{
649 exception_enter(regs);
632#ifdef CONFIG_MATH_EMULATION 650#ifdef CONFIG_MATH_EMULATION
633 if (read_cr0() & X86_CR0_EM) { 651 if (read_cr0() & X86_CR0_EM) {
634 struct math_emu_info info = { }; 652 struct math_emu_info info = { };
@@ -637,6 +655,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)
637 655
638 info.regs = regs; 656 info.regs = regs;
639 math_emulate(&info); 657 math_emulate(&info);
658 exception_exit(regs);
640 return; 659 return;
641 } 660 }
642#endif 661#endif
@@ -644,12 +663,15 @@ do_device_not_available(struct pt_regs *regs, long error_code)
644#ifdef CONFIG_X86_32 663#ifdef CONFIG_X86_32
645 conditional_sti(regs); 664 conditional_sti(regs);
646#endif 665#endif
666 exception_exit(regs);
647} 667}
648 668
649#ifdef CONFIG_X86_32 669#ifdef CONFIG_X86_32
650dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) 670dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
651{ 671{
652 siginfo_t info; 672 siginfo_t info;
673
674 exception_enter(regs);
653 local_irq_enable(); 675 local_irq_enable();
654 676
655 info.si_signo = SIGILL; 677 info.si_signo = SIGILL;
@@ -657,10 +679,11 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
657 info.si_code = ILL_BADSTK; 679 info.si_code = ILL_BADSTK;
658 info.si_addr = NULL; 680 info.si_addr = NULL;
659 if (notify_die(DIE_TRAP, "iret exception", regs, error_code, 681 if (notify_die(DIE_TRAP, "iret exception", regs, error_code,
660 X86_TRAP_IRET, SIGILL) == NOTIFY_STOP) 682 X86_TRAP_IRET, SIGILL) != NOTIFY_STOP) {
661 return; 683 do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
662 do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code, 684 &info);
663 &info); 685 }
686 exception_exit(regs);
664} 687}
665#endif 688#endif
666 689
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 76dcd9d8e0bc..7dde46d68a25 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -18,6 +18,7 @@
18#include <asm/pgalloc.h> /* pgd_*(), ... */ 18#include <asm/pgalloc.h> /* pgd_*(), ... */
19#include <asm/kmemcheck.h> /* kmemcheck_*(), ... */ 19#include <asm/kmemcheck.h> /* kmemcheck_*(), ... */
20#include <asm/fixmap.h> /* VSYSCALL_START */ 20#include <asm/fixmap.h> /* VSYSCALL_START */
21#include <asm/rcu.h> /* exception_enter(), ... */
21 22
22/* 23/*
23 * Page fault error code bits: 24 * Page fault error code bits:
@@ -1000,8 +1001,8 @@ static int fault_in_kernel_space(unsigned long address)
1000 * and the problem, and then passes it off to one of the appropriate 1001 * and the problem, and then passes it off to one of the appropriate
1001 * routines. 1002 * routines.
1002 */ 1003 */
1003dotraplinkage void __kprobes 1004static void __kprobes
1004do_page_fault(struct pt_regs *regs, unsigned long error_code) 1005__do_page_fault(struct pt_regs *regs, unsigned long error_code)
1005{ 1006{
1006 struct vm_area_struct *vma; 1007 struct vm_area_struct *vma;
1007 struct task_struct *tsk; 1008 struct task_struct *tsk;
@@ -1209,3 +1210,11 @@ good_area:
1209 1210
1210 up_read(&mm->mmap_sem); 1211 up_read(&mm->mmap_sem);
1211} 1212}
1213
1214dotraplinkage void __kprobes
1215do_page_fault(struct pt_regs *regs, unsigned long error_code)
1216{
1217 exception_enter(regs);
1218 __do_page_fault(regs, error_code);
1219 exception_exit(regs);
1220}