aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/traps.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/traps.c')
-rw-r--r--arch/x86/kernel/traps.c68
1 files changed, 42 insertions, 26 deletions
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 68bda7a84159..ff6d2271cbe2 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -12,6 +12,7 @@
12 12
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14 14
15#include <linux/context_tracking.h>
15#include <linux/interrupt.h> 16#include <linux/interrupt.h>
16#include <linux/kallsyms.h> 17#include <linux/kallsyms.h>
17#include <linux/spinlock.h> 18#include <linux/spinlock.h>
@@ -55,8 +56,6 @@
55#include <asm/i387.h> 56#include <asm/i387.h>
56#include <asm/fpu-internal.h> 57#include <asm/fpu-internal.h>
57#include <asm/mce.h> 58#include <asm/mce.h>
58#include <asm/context_tracking.h>
59
60#include <asm/mach_traps.h> 59#include <asm/mach_traps.h>
61 60
62#ifdef CONFIG_X86_64 61#ifdef CONFIG_X86_64
@@ -176,34 +175,38 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs,
176#define DO_ERROR(trapnr, signr, str, name) \ 175#define DO_ERROR(trapnr, signr, str, name) \
177dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ 176dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
178{ \ 177{ \
179 exception_enter(regs); \ 178 enum ctx_state prev_state; \
179 \
180 prev_state = exception_enter(); \
180 if (notify_die(DIE_TRAP, str, regs, error_code, \ 181 if (notify_die(DIE_TRAP, str, regs, error_code, \
181 trapnr, signr) == NOTIFY_STOP) { \ 182 trapnr, signr) == NOTIFY_STOP) { \
182 exception_exit(regs); \ 183 exception_exit(prev_state); \
183 return; \ 184 return; \
184 } \ 185 } \
185 conditional_sti(regs); \ 186 conditional_sti(regs); \
186 do_trap(trapnr, signr, str, regs, error_code, NULL); \ 187 do_trap(trapnr, signr, str, regs, error_code, NULL); \
187 exception_exit(regs); \ 188 exception_exit(prev_state); \
188} 189}
189 190
190#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ 191#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \
191dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ 192dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
192{ \ 193{ \
193 siginfo_t info; \ 194 siginfo_t info; \
195 enum ctx_state prev_state; \
196 \
194 info.si_signo = signr; \ 197 info.si_signo = signr; \
195 info.si_errno = 0; \ 198 info.si_errno = 0; \
196 info.si_code = sicode; \ 199 info.si_code = sicode; \
197 info.si_addr = (void __user *)siaddr; \ 200 info.si_addr = (void __user *)siaddr; \
198 exception_enter(regs); \ 201 prev_state = exception_enter(); \
199 if (notify_die(DIE_TRAP, str, regs, error_code, \ 202 if (notify_die(DIE_TRAP, str, regs, error_code, \
200 trapnr, signr) == NOTIFY_STOP) { \ 203 trapnr, signr) == NOTIFY_STOP) { \
201 exception_exit(regs); \ 204 exception_exit(prev_state); \
202 return; \ 205 return; \
203 } \ 206 } \
204 conditional_sti(regs); \ 207 conditional_sti(regs); \
205 do_trap(trapnr, signr, str, regs, error_code, &info); \ 208 do_trap(trapnr, signr, str, regs, error_code, &info); \
206 exception_exit(regs); \ 209 exception_exit(prev_state); \
207} 210}
208 211
209DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV, 212DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV,
@@ -226,14 +229,16 @@ DO_ERROR_INFO(X86_TRAP_AC, SIGBUS, "alignment check", alignment_check,
226/* Runs on IST stack */ 229/* Runs on IST stack */
227dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) 230dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code)
228{ 231{
229 exception_enter(regs); 232 enum ctx_state prev_state;
233
234 prev_state = exception_enter();
230 if (notify_die(DIE_TRAP, "stack segment", regs, error_code, 235 if (notify_die(DIE_TRAP, "stack segment", regs, error_code,
231 X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) { 236 X86_TRAP_SS, SIGBUS) != NOTIFY_STOP) {
232 preempt_conditional_sti(regs); 237 preempt_conditional_sti(regs);
233 do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL); 238 do_trap(X86_TRAP_SS, SIGBUS, "stack segment", regs, error_code, NULL);
234 preempt_conditional_cli(regs); 239 preempt_conditional_cli(regs);
235 } 240 }
236 exception_exit(regs); 241 exception_exit(prev_state);
237} 242}
238 243
239dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) 244dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
@@ -241,7 +246,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
241 static const char str[] = "double fault"; 246 static const char str[] = "double fault";
242 struct task_struct *tsk = current; 247 struct task_struct *tsk = current;
243 248
244 exception_enter(regs); 249 exception_enter();
245 /* Return not checked because double check cannot be ignored */ 250 /* Return not checked because double check cannot be ignored */
246 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);
247 252
@@ -261,8 +266,9 @@ dotraplinkage void __kprobes
261do_general_protection(struct pt_regs *regs, long error_code) 266do_general_protection(struct pt_regs *regs, long error_code)
262{ 267{
263 struct task_struct *tsk; 268 struct task_struct *tsk;
269 enum ctx_state prev_state;
264 270
265 exception_enter(regs); 271 prev_state = exception_enter();
266 conditional_sti(regs); 272 conditional_sti(regs);
267 273
268#ifdef CONFIG_X86_32 274#ifdef CONFIG_X86_32
@@ -300,12 +306,14 @@ do_general_protection(struct pt_regs *regs, long error_code)
300 306
301 force_sig(SIGSEGV, tsk); 307 force_sig(SIGSEGV, tsk);
302exit: 308exit:
303 exception_exit(regs); 309 exception_exit(prev_state);
304} 310}
305 311
306/* May run on IST stack. */ 312/* May run on IST stack. */
307dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code) 313dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code)
308{ 314{
315 enum ctx_state prev_state;
316
309#ifdef CONFIG_DYNAMIC_FTRACE 317#ifdef CONFIG_DYNAMIC_FTRACE
310 /* 318 /*
311 * ftrace must be first, everything else may cause a recursive crash. 319 * ftrace must be first, everything else may cause a recursive crash.
@@ -315,7 +323,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
315 ftrace_int3_handler(regs)) 323 ftrace_int3_handler(regs))
316 return; 324 return;
317#endif 325#endif
318 exception_enter(regs); 326 prev_state = exception_enter();
319#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP 327#ifdef CONFIG_KGDB_LOW_LEVEL_TRAP
320 if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, 328 if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
321 SIGTRAP) == NOTIFY_STOP) 329 SIGTRAP) == NOTIFY_STOP)
@@ -336,7 +344,7 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
336 preempt_conditional_cli(regs); 344 preempt_conditional_cli(regs);
337 debug_stack_usage_dec(); 345 debug_stack_usage_dec();
338exit: 346exit:
339 exception_exit(regs); 347 exception_exit(prev_state);
340} 348}
341 349
342#ifdef CONFIG_X86_64 350#ifdef CONFIG_X86_64
@@ -393,11 +401,12 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
393dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) 401dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
394{ 402{
395 struct task_struct *tsk = current; 403 struct task_struct *tsk = current;
404 enum ctx_state prev_state;
396 int user_icebp = 0; 405 int user_icebp = 0;
397 unsigned long dr6; 406 unsigned long dr6;
398 int si_code; 407 int si_code;
399 408
400 exception_enter(regs); 409 prev_state = exception_enter();
401 410
402 get_debugreg(dr6, 6); 411 get_debugreg(dr6, 6);
403 412
@@ -467,7 +476,7 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
467 debug_stack_usage_dec(); 476 debug_stack_usage_dec();
468 477
469exit: 478exit:
470 exception_exit(regs); 479 exception_exit(prev_state);
471} 480}
472 481
473/* 482/*
@@ -561,17 +570,21 @@ void math_error(struct pt_regs *regs, int error_code, int trapnr)
561 570
562dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) 571dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code)
563{ 572{
564 exception_enter(regs); 573 enum ctx_state prev_state;
574
575 prev_state = exception_enter();
565 math_error(regs, error_code, X86_TRAP_MF); 576 math_error(regs, error_code, X86_TRAP_MF);
566 exception_exit(regs); 577 exception_exit(prev_state);
567} 578}
568 579
569dotraplinkage void 580dotraplinkage void
570do_simd_coprocessor_error(struct pt_regs *regs, long error_code) 581do_simd_coprocessor_error(struct pt_regs *regs, long error_code)
571{ 582{
572 exception_enter(regs); 583 enum ctx_state prev_state;
584
585 prev_state = exception_enter();
573 math_error(regs, error_code, X86_TRAP_XF); 586 math_error(regs, error_code, X86_TRAP_XF);
574 exception_exit(regs); 587 exception_exit(prev_state);
575} 588}
576 589
577dotraplinkage void 590dotraplinkage void
@@ -639,7 +652,9 @@ EXPORT_SYMBOL_GPL(math_state_restore);
639dotraplinkage void __kprobes 652dotraplinkage void __kprobes
640do_device_not_available(struct pt_regs *regs, long error_code) 653do_device_not_available(struct pt_regs *regs, long error_code)
641{ 654{
642 exception_enter(regs); 655 enum ctx_state prev_state;
656
657 prev_state = exception_enter();
643 BUG_ON(use_eager_fpu()); 658 BUG_ON(use_eager_fpu());
644 659
645#ifdef CONFIG_MATH_EMULATION 660#ifdef CONFIG_MATH_EMULATION
@@ -650,7 +665,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)
650 665
651 info.regs = regs; 666 info.regs = regs;
652 math_emulate(&info); 667 math_emulate(&info);
653 exception_exit(regs); 668 exception_exit(prev_state);
654 return; 669 return;
655 } 670 }
656#endif 671#endif
@@ -658,15 +673,16 @@ do_device_not_available(struct pt_regs *regs, long error_code)
658#ifdef CONFIG_X86_32 673#ifdef CONFIG_X86_32
659 conditional_sti(regs); 674 conditional_sti(regs);
660#endif 675#endif
661 exception_exit(regs); 676 exception_exit(prev_state);
662} 677}
663 678
664#ifdef CONFIG_X86_32 679#ifdef CONFIG_X86_32
665dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) 680dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
666{ 681{
667 siginfo_t info; 682 siginfo_t info;
683 enum ctx_state prev_state;
668 684
669 exception_enter(regs); 685 prev_state = exception_enter();
670 local_irq_enable(); 686 local_irq_enable();
671 687
672 info.si_signo = SIGILL; 688 info.si_signo = SIGILL;
@@ -678,7 +694,7 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code)
678 do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code, 694 do_trap(X86_TRAP_IRET, SIGILL, "iret exception", regs, error_code,
679 &info); 695 &info);
680 } 696 }
681 exception_exit(regs); 697 exception_exit(prev_state);
682} 698}
683#endif 699#endif
684 700