aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/traps.c
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2012-07-11 14:26:35 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2012-09-26 09:47:07 -0400
commit6ba3c97a38803883c2eee489505796cb0a727122 (patch)
treeb6400bf2e10bf8d55b63eae35ddb93f3a9e9b270 /arch/x86/kernel/traps.c
parentef3f628872c838933a279d0d7e63e707783c9710 (diff)
x86: Exception hooks for userspace RCU extended QS
Add necessary hooks to x86 exception for userspace RCU extended quiescent state support. This includes traps, page fault, debug exceptions, etc... Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Cc: Alessio Igor Bogani <abogani@kernel.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Avi Kivity <avi@redhat.com> Cc: Chris Metcalf <cmetcalf@tilera.com> Cc: Christoph Lameter <cl@linux.com> Cc: Geoff Levand <geoff@infradead.org> Cc: Gilad Ben Yossef <gilad@benyossef.com> Cc: Hakan Akkan <hakanakkan@gmail.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Ingo Molnar <mingo@kernel.org> Cc: Josh Triplett <josh@joshtriplett.org> Cc: Kevin Hilman <khilman@ti.com> Cc: Max Krasnyansky <maxk@qualcomm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephen Hemminger <shemminger@vyatta.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Sven-Thorsten Dietrich <thebigcorporation@gmail.com> Cc: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'arch/x86/kernel/traps.c')
-rw-r--r--arch/x86/kernel/traps.c81
1 files changed, 55 insertions, 26 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 74850e559449..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,27 +267,28 @@ 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 local_irq_enable(); 275 local_irq_enable();
263 handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); 276 handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code);
264 return; 277 goto exit;
265 } 278 }
266#endif 279#endif
267 280
268 tsk = current; 281 tsk = current;
269 if (!user_mode(regs)) { 282 if (!user_mode(regs)) {
270 if (fixup_exception(regs)) 283 if (fixup_exception(regs))
271 return; 284 goto exit;
272 285
273 tsk->thread.error_code = error_code; 286 tsk->thread.error_code = error_code;
274 tsk->thread.trap_nr = X86_TRAP_GP; 287 tsk->thread.trap_nr = X86_TRAP_GP;
275 if (!notify_die(DIE_GPF, "general protection fault", regs, error_code, 288 if (notify_die(DIE_GPF, "general protection fault", regs, error_code,
276 X86_TRAP_GP, SIGSEGV) == NOTIFY_STOP) 289 X86_TRAP_GP, SIGSEGV) != NOTIFY_STOP)
277 die("general protection fault", regs, error_code); 290 die("general protection fault", regs, error_code);
278 return; 291 goto exit;
279 } 292 }
280 293
281 tsk->thread.error_code = error_code; 294 tsk->thread.error_code = error_code;
@@ -291,7 +304,8 @@ do_general_protection(struct pt_regs *regs, long error_code)
291 } 304 }
292 305
293 force_sig(SIGSEGV, tsk); 306 force_sig(SIGSEGV, tsk);
294 return; 307exit:
308 exception_exit(regs);
295} 309}
296 310
297/* May run on IST stack. */ 311/* May run on IST stack. */
@@ -306,15 +320,16 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
306 ftrace_int3_handler(regs)) 320 ftrace_int3_handler(regs))
307 return; 321 return;
308#endif 322#endif
323 exception_enter(regs);
309#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP 324#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
310 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,
311 SIGTRAP) == NOTIFY_STOP) 326 SIGTRAP) == NOTIFY_STOP)
312 return; 327 goto exit;
313#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ 328#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
314 329
315 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,
316 SIGTRAP) == NOTIFY_STOP) 331 SIGTRAP) == NOTIFY_STOP)
317 return; 332 goto exit;
318 333
319 /* 334 /*
320 * Let others (NMI) know that the debug stack is in use 335 * Let others (NMI) know that the debug stack is in use
@@ -325,6 +340,8 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
325 do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL); 340 do_trap(X86_TRAP_BP, SIGTRAP, "int3", regs, error_code, NULL);
326 preempt_conditional_cli(regs); 341 preempt_conditional_cli(regs);
327 debug_stack_usage_dec(); 342 debug_stack_usage_dec();
343exit:
344 exception_exit(regs);
328} 345}
329 346
330#ifdef CONFIG_X86_64 347#ifdef CONFIG_X86_64
@@ -385,6 +402,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
385 unsigned long dr6; 402 unsigned long dr6;
386 int si_code; 403 int si_code;
387 404
405 exception_enter(regs);
406
388 get_debugreg(dr6, 6); 407 get_debugreg(dr6, 6);
389 408
390 /* Filter out all the reserved bits which are preset to 1 */ 409 /* Filter out all the reserved bits which are preset to 1 */
@@ -400,7 +419,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
400 419
401 /* Catch kmemcheck conditions first of all! */ 420 /* Catch kmemcheck conditions first of all! */
402 if ((dr6 & DR_STEP) && kmemcheck_trap(regs)) 421 if ((dr6 & DR_STEP) && kmemcheck_trap(regs))
403 return; 422 goto exit;
404 423
405 /* DR6 may or may not be cleared by the CPU */ 424 /* DR6 may or may not be cleared by the CPU */
406 set_debugreg(0, 6); 425 set_debugreg(0, 6);
@@ -415,7 +434,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
415 434
416 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,
417 SIGTRAP) == NOTIFY_STOP) 436 SIGTRAP) == NOTIFY_STOP)
418 return; 437 goto exit;
419 438
420 /* 439 /*
421 * Let others (NMI) know that the debug stack is in use 440 * Let others (NMI) know that the debug stack is in use
@@ -431,7 +450,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
431 X86_TRAP_DB); 450 X86_TRAP_DB);
432 preempt_conditional_cli(regs); 451 preempt_conditional_cli(regs);
433 debug_stack_usage_dec(); 452 debug_stack_usage_dec();
434 return; 453 goto exit;
435 } 454 }
436 455
437 /* 456 /*
@@ -452,7 +471,8 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
452 preempt_conditional_cli(regs); 471 preempt_conditional_cli(regs);
453 debug_stack_usage_dec(); 472 debug_stack_usage_dec();
454 473
455 return; 474exit:
475 exception_exit(regs);
456} 476}
457 477
458/* 478/*
@@ -549,14 +569,17 @@ dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
549#ifdef CONFIG_X86_32 569#ifdef CONFIG_X86_32
550 ignore_fpu_irq = 1; 570 ignore_fpu_irq = 1;
551#endif 571#endif
552 572 exception_enter(regs);
553 math_error(regs, error_code, X86_TRAP_MF); 573 math_error(regs, error_code, X86_TRAP_MF);
574 exception_exit(regs);
554} 575}
555 576
556dotraplinkage void 577dotraplinkage void
557do_simd_coprocessor_error(struct pt_regs *regs, long error_code) 578do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
558{ 579{
580 exception_enter(regs);
559 math_error(regs, error_code, X86_TRAP_XF); 581 math_error(regs, error_code, X86_TRAP_XF);
582 exception_exit(regs);
560} 583}
561 584
562dotraplinkage void 585dotraplinkage void
@@ -623,6 +646,7 @@ EXPORT_SYMBOL_GPL(math_state_restore);
623dotraplinkage void __kprobes 646dotraplinkage void __kprobes
624do_device_not_available(struct pt_regs *regs, long error_code) 647do_device_not_available(struct pt_regs *regs, long error_code)
625{ 648{
649 exception_enter(regs);
626#ifdef CONFIG_MATH_EMULATION 650#ifdef CONFIG_MATH_EMULATION
627 if (read_cr0() & X86_CR0_EM) { 651 if (read_cr0() & X86_CR0_EM) {
628 struct math_emu_info info = { }; 652 struct math_emu_info info = { };
@@ -631,6 +655,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)
631 655
632 info.regs = regs; 656 info.regs = regs;
633 math_emulate(&info); 657 math_emulate(&info);
658 exception_exit(regs);
634 return; 659 return;
635 } 660 }
636#endif 661#endif
@@ -638,12 +663,15 @@ do_device_not_available(struct pt_regs *regs, long error_code)
638#ifdef CONFIG_X86_32 663#ifdef CONFIG_X86_32
639 conditional_sti(regs); 664 conditional_sti(regs);
640#endif 665#endif
666 exception_exit(regs);
641} 667}
642 668
643#ifdef CONFIG_X86_32 669#ifdef CONFIG_X86_32
644dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) 670dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
645{ 671{
646 siginfo_t info; 672 siginfo_t info;
673
674 exception_enter(regs);
647 local_irq_enable(); 675 local_irq_enable();
648 676
649 info.si_signo = SIGILL; 677 info.si_signo = SIGILL;
@@ -651,10 +679,11 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
651 info.si_code = ILL_BADSTK; 679 info.si_code = ILL_BADSTK;
652 info.si_addr = NULL; 680 info.si_addr = NULL;
653 if (notify_die(DIE_TRAP, "iret exception", regs, error_code, 681 if (notify_die(DIE_TRAP, "iret exception", regs, error_code,
654 X86_TRAP_IRET, SIGILL) == NOTIFY_STOP) 682 X86_TRAP_IRET, SIGILL) != NOTIFY_STOP) {
655 return; 683 do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
656 do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code, 684 &info);
657 &info); 685 }
686 exception_exit(regs);
658} 687}
659#endif 688#endif
660 689