diff options
Diffstat (limited to 'arch/x86/kernel/traps.c')
-rw-r--r-- | arch/x86/kernel/traps.c | 68 |
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) \ |
177 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ | 176 | dotraplinkage 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) \ |
191 | dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \ | 192 | dotraplinkage 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 | ||
209 | DO_ERROR_INFO(X86_TRAP_DE, SIGFPE, "divide error", divide_error, FPE_INTDIV, | 212 | DO_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 */ |
227 | dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) | 230 | dotraplinkage 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 | ||
239 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) | 244 | dotraplinkage 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 | |||
261 | do_general_protection(struct pt_regs *regs, long error_code) | 266 | do_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); |
302 | exit: | 308 | exit: |
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. */ |
307 | dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_code) | 313 | dotraplinkage 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(); |
338 | exit: | 346 | exit: |
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) | |||
393 | dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | 401 | dotraplinkage 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 | ||
469 | exit: | 478 | exit: |
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 | ||
562 | dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) | 571 | dotraplinkage 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 | ||
569 | dotraplinkage void | 580 | dotraplinkage void |
570 | do_simd_coprocessor_error(struct pt_regs *regs, long error_code) | 581 | do_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 | ||
577 | dotraplinkage void | 590 | dotraplinkage void |
@@ -639,7 +652,9 @@ EXPORT_SYMBOL_GPL(math_state_restore); | |||
639 | dotraplinkage void __kprobes | 652 | dotraplinkage void __kprobes |
640 | do_device_not_available(struct pt_regs *regs, long error_code) | 653 | do_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 |
665 | dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) | 680 | dotraplinkage 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 | ||