diff options
author | Alexander van Heukelum <heukelum@fastmail.fm> | 2008-10-03 16:00:39 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-13 04:33:28 -0400 |
commit | 081f75bbdc86de53537e1b5aca01de72bd2fea6b (patch) | |
tree | 739b7954495fb63559b0184b76cc32c63aa2bdcd /arch/x86 | |
parent | c1d518c8422ff7d3f377958771b265753028579c (diff) |
traps: x86: make traps_32.c and traps_64.c equal
Use CONFIG_X86_64/CONFIG_X86_32 to condtionally compile the
parts needed for x86_64 or i386 only.
Runs a small userspace for a number of minimal configurations
and boots the defconfigs.
Signed-off-by: Alexander van Heukelum <heukelum@fastmail.fm>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r-- | arch/x86/kernel/traps_32.c | 173 | ||||
-rw-r--r-- | arch/x86/kernel/traps_64.c | 368 |
2 files changed, 536 insertions, 5 deletions
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 076739863d24..ffb131f74f78 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c | |||
@@ -48,7 +48,6 @@ | |||
48 | 48 | ||
49 | #include <asm/stacktrace.h> | 49 | #include <asm/stacktrace.h> |
50 | #include <asm/processor.h> | 50 | #include <asm/processor.h> |
51 | #include <asm/kmemcheck.h> | ||
52 | #include <asm/debugreg.h> | 51 | #include <asm/debugreg.h> |
53 | #include <asm/atomic.h> | 52 | #include <asm/atomic.h> |
54 | #include <asm/system.h> | 53 | #include <asm/system.h> |
@@ -59,6 +58,11 @@ | |||
59 | 58 | ||
60 | #include <mach_traps.h> | 59 | #include <mach_traps.h> |
61 | 60 | ||
61 | #ifdef CONFIG_X86_64 | ||
62 | #include <asm/pgalloc.h> | ||
63 | #include <asm/proto.h> | ||
64 | #include <asm/pda.h> | ||
65 | #else | ||
62 | #include <asm/processor-flags.h> | 66 | #include <asm/processor-flags.h> |
63 | #include <asm/arch_hooks.h> | 67 | #include <asm/arch_hooks.h> |
64 | #include <asm/nmi.h> | 68 | #include <asm/nmi.h> |
@@ -83,6 +87,7 @@ char ignore_fpu_irq; | |||
83 | */ | 87 | */ |
84 | gate_desc idt_table[256] | 88 | gate_desc idt_table[256] |
85 | __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; | 89 | __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; |
90 | #endif | ||
86 | 91 | ||
87 | static int ignore_nmis; | 92 | static int ignore_nmis; |
88 | 93 | ||
@@ -106,6 +111,7 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) | |||
106 | dec_preempt_count(); | 111 | dec_preempt_count(); |
107 | } | 112 | } |
108 | 113 | ||
114 | #ifdef CONFIG_X86_32 | ||
109 | static inline void | 115 | static inline void |
110 | die_if_kernel(const char *str, struct pt_regs *regs, long err) | 116 | die_if_kernel(const char *str, struct pt_regs *regs, long err) |
111 | { | 117 | { |
@@ -153,6 +159,7 @@ static int lazy_iobitmap_copy(void) | |||
153 | 159 | ||
154 | return 0; | 160 | return 0; |
155 | } | 161 | } |
162 | #endif | ||
156 | 163 | ||
157 | static void __kprobes | 164 | static void __kprobes |
158 | do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, | 165 | do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, |
@@ -160,6 +167,7 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, | |||
160 | { | 167 | { |
161 | struct task_struct *tsk = current; | 168 | struct task_struct *tsk = current; |
162 | 169 | ||
170 | #ifdef CONFIG_X86_32 | ||
163 | if (regs->flags & X86_VM_MASK) { | 171 | if (regs->flags & X86_VM_MASK) { |
164 | /* | 172 | /* |
165 | * traps 0, 1, 3, 4, and 5 should be forwarded to vm86. | 173 | * traps 0, 1, 3, 4, and 5 should be forwarded to vm86. |
@@ -169,11 +177,14 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, | |||
169 | goto vm86_trap; | 177 | goto vm86_trap; |
170 | goto trap_signal; | 178 | goto trap_signal; |
171 | } | 179 | } |
180 | #endif | ||
172 | 181 | ||
173 | if (!user_mode(regs)) | 182 | if (!user_mode(regs)) |
174 | goto kernel_trap; | 183 | goto kernel_trap; |
175 | 184 | ||
185 | #ifdef CONFIG_X86_32 | ||
176 | trap_signal: | 186 | trap_signal: |
187 | #endif | ||
177 | /* | 188 | /* |
178 | * We want error_code and trap_no set for userspace faults and | 189 | * We want error_code and trap_no set for userspace faults and |
179 | * kernelspace faults which result in die(), but not | 190 | * kernelspace faults which result in die(), but not |
@@ -186,6 +197,18 @@ trap_signal: | |||
186 | tsk->thread.error_code = error_code; | 197 | tsk->thread.error_code = error_code; |
187 | tsk->thread.trap_no = trapnr; | 198 | tsk->thread.trap_no = trapnr; |
188 | 199 | ||
200 | #ifdef CONFIG_X86_64 | ||
201 | if (show_unhandled_signals && unhandled_signal(tsk, signr) && | ||
202 | printk_ratelimit()) { | ||
203 | printk(KERN_INFO | ||
204 | "%s[%d] trap %s ip:%lx sp:%lx error:%lx", | ||
205 | tsk->comm, tsk->pid, str, | ||
206 | regs->ip, regs->sp, error_code); | ||
207 | print_vma_addr(" in ", regs->ip); | ||
208 | printk("\n"); | ||
209 | } | ||
210 | #endif | ||
211 | |||
189 | if (info) | 212 | if (info) |
190 | force_sig_info(signr, info, tsk); | 213 | force_sig_info(signr, info, tsk); |
191 | else | 214 | else |
@@ -200,11 +223,13 @@ kernel_trap: | |||
200 | } | 223 | } |
201 | return; | 224 | return; |
202 | 225 | ||
226 | #ifdef CONFIG_X86_32 | ||
203 | vm86_trap: | 227 | vm86_trap: |
204 | if (handle_vm86_trap((struct kernel_vm86_regs *) regs, | 228 | if (handle_vm86_trap((struct kernel_vm86_regs *) regs, |
205 | error_code, trapnr)) | 229 | error_code, trapnr)) |
206 | goto trap_signal; | 230 | goto trap_signal; |
207 | return; | 231 | return; |
232 | #endif | ||
208 | } | 233 | } |
209 | 234 | ||
210 | #define DO_ERROR(trapnr, signr, str, name) \ | 235 | #define DO_ERROR(trapnr, signr, str, name) \ |
@@ -239,9 +264,41 @@ DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip) | |||
239 | DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) | 264 | DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) |
240 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) | 265 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) |
241 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) | 266 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) |
267 | #ifdef CONFIG_X86_32 | ||
242 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) | 268 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) |
269 | #endif | ||
243 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) | 270 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) |
244 | 271 | ||
272 | #ifdef CONFIG_X86_64 | ||
273 | /* Runs on IST stack */ | ||
274 | dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) | ||
275 | { | ||
276 | if (notify_die(DIE_TRAP, "stack segment", regs, error_code, | ||
277 | 12, SIGBUS) == NOTIFY_STOP) | ||
278 | return; | ||
279 | preempt_conditional_sti(regs); | ||
280 | do_trap(12, SIGBUS, "stack segment", regs, error_code, NULL); | ||
281 | preempt_conditional_cli(regs); | ||
282 | } | ||
283 | |||
284 | dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) | ||
285 | { | ||
286 | static const char str[] = "double fault"; | ||
287 | struct task_struct *tsk = current; | ||
288 | |||
289 | /* Return not checked because double check cannot be ignored */ | ||
290 | notify_die(DIE_TRAP, str, regs, error_code, 8, SIGSEGV); | ||
291 | |||
292 | tsk->thread.error_code = error_code; | ||
293 | tsk->thread.trap_no = 8; | ||
294 | |||
295 | /* This is always a kernel trap and never fixable (and thus must | ||
296 | never return). */ | ||
297 | for (;;) | ||
298 | die(str, regs, error_code); | ||
299 | } | ||
300 | #endif | ||
301 | |||
245 | dotraplinkage void __kprobes | 302 | dotraplinkage void __kprobes |
246 | do_general_protection(struct pt_regs *regs, long error_code) | 303 | do_general_protection(struct pt_regs *regs, long error_code) |
247 | { | 304 | { |
@@ -249,6 +306,7 @@ do_general_protection(struct pt_regs *regs, long error_code) | |||
249 | 306 | ||
250 | conditional_sti(regs); | 307 | conditional_sti(regs); |
251 | 308 | ||
309 | #ifdef CONFIG_X86_32 | ||
252 | if (lazy_iobitmap_copy()) { | 310 | if (lazy_iobitmap_copy()) { |
253 | /* restart the faulting instruction */ | 311 | /* restart the faulting instruction */ |
254 | return; | 312 | return; |
@@ -256,6 +314,7 @@ do_general_protection(struct pt_regs *regs, long error_code) | |||
256 | 314 | ||
257 | if (regs->flags & X86_VM_MASK) | 315 | if (regs->flags & X86_VM_MASK) |
258 | goto gp_in_vm86; | 316 | goto gp_in_vm86; |
317 | #endif | ||
259 | 318 | ||
260 | tsk = current; | 319 | tsk = current; |
261 | if (!user_mode(regs)) | 320 | if (!user_mode(regs)) |
@@ -277,10 +336,12 @@ do_general_protection(struct pt_regs *regs, long error_code) | |||
277 | force_sig(SIGSEGV, tsk); | 336 | force_sig(SIGSEGV, tsk); |
278 | return; | 337 | return; |
279 | 338 | ||
339 | #ifdef CONFIG_X86_32 | ||
280 | gp_in_vm86: | 340 | gp_in_vm86: |
281 | local_irq_enable(); | 341 | local_irq_enable(); |
282 | handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); | 342 | handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); |
283 | return; | 343 | return; |
344 | #endif | ||
284 | 345 | ||
285 | gp_in_kernel: | 346 | gp_in_kernel: |
286 | if (fixup_exception(regs)) | 347 | if (fixup_exception(regs)) |
@@ -368,6 +429,7 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs) | |||
368 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | 429 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); |
369 | } | 430 | } |
370 | 431 | ||
432 | #ifdef CONFIG_X86_32 | ||
371 | static DEFINE_SPINLOCK(nmi_print_lock); | 433 | static DEFINE_SPINLOCK(nmi_print_lock); |
372 | 434 | ||
373 | void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) | 435 | void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) |
@@ -402,6 +464,7 @@ void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) | |||
402 | 464 | ||
403 | do_exit(SIGSEGV); | 465 | do_exit(SIGSEGV); |
404 | } | 466 | } |
467 | #endif | ||
405 | 468 | ||
406 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | 469 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) |
407 | { | 470 | { |
@@ -441,11 +504,13 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | |||
441 | mem_parity_error(reason, regs); | 504 | mem_parity_error(reason, regs); |
442 | if (reason & 0x40) | 505 | if (reason & 0x40) |
443 | io_check_error(reason, regs); | 506 | io_check_error(reason, regs); |
507 | #ifdef CONFIG_X86_32 | ||
444 | /* | 508 | /* |
445 | * Reassert NMI in case it became active meanwhile | 509 | * Reassert NMI in case it became active meanwhile |
446 | * as it's edge-triggered: | 510 | * as it's edge-triggered: |
447 | */ | 511 | */ |
448 | reassert_nmi(); | 512 | reassert_nmi(); |
513 | #endif | ||
449 | } | 514 | } |
450 | 515 | ||
451 | dotraplinkage notrace __kprobes void | 516 | dotraplinkage notrace __kprobes void |
@@ -453,7 +518,11 @@ do_nmi(struct pt_regs *regs, long error_code) | |||
453 | { | 518 | { |
454 | nmi_enter(); | 519 | nmi_enter(); |
455 | 520 | ||
521 | #ifdef CONFIG_X86_32 | ||
456 | { int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); } | 522 | { int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); } |
523 | #else | ||
524 | add_pda(__nmi_count, 1); | ||
525 | #endif | ||
457 | 526 | ||
458 | if (!ignore_nmis) | 527 | if (!ignore_nmis) |
459 | default_do_nmi(regs); | 528 | default_do_nmi(regs); |
@@ -491,6 +560,29 @@ dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) | |||
491 | preempt_conditional_cli(regs); | 560 | preempt_conditional_cli(regs); |
492 | } | 561 | } |
493 | 562 | ||
563 | #ifdef CONFIG_X86_64 | ||
564 | /* Help handler running on IST stack to switch back to user stack | ||
565 | for scheduling or signal handling. The actual stack switch is done in | ||
566 | entry.S */ | ||
567 | asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) | ||
568 | { | ||
569 | struct pt_regs *regs = eregs; | ||
570 | /* Did already sync */ | ||
571 | if (eregs == (struct pt_regs *)eregs->sp) | ||
572 | ; | ||
573 | /* Exception from user space */ | ||
574 | else if (user_mode(eregs)) | ||
575 | regs = task_pt_regs(current); | ||
576 | /* Exception from kernel and interrupts are enabled. Move to | ||
577 | kernel process stack. */ | ||
578 | else if (eregs->flags & X86_EFLAGS_IF) | ||
579 | regs = (struct pt_regs *)(eregs->sp -= sizeof(struct pt_regs)); | ||
580 | if (eregs != regs) | ||
581 | *regs = *eregs; | ||
582 | return regs; | ||
583 | } | ||
584 | #endif | ||
585 | |||
494 | /* | 586 | /* |
495 | * Our handling of the processor debug registers is non-trivial. | 587 | * Our handling of the processor debug registers is non-trivial. |
496 | * We do not clear them on entry and exit from the kernel. Therefore | 588 | * We do not clear them on entry and exit from the kernel. Therefore |
@@ -542,8 +634,10 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
542 | goto clear_dr7; | 634 | goto clear_dr7; |
543 | } | 635 | } |
544 | 636 | ||
637 | #ifdef CONFIG_X86_32 | ||
545 | if (regs->flags & X86_VM_MASK) | 638 | if (regs->flags & X86_VM_MASK) |
546 | goto debug_vm86; | 639 | goto debug_vm86; |
640 | #endif | ||
547 | 641 | ||
548 | /* Save debug status register where ptrace can see it */ | 642 | /* Save debug status register where ptrace can see it */ |
549 | tsk->thread.debugreg6 = condition; | 643 | tsk->thread.debugreg6 = condition; |
@@ -570,10 +664,12 @@ clear_dr7: | |||
570 | preempt_conditional_cli(regs); | 664 | preempt_conditional_cli(regs); |
571 | return; | 665 | return; |
572 | 666 | ||
667 | #ifdef CONFIG_X86_32 | ||
573 | debug_vm86: | 668 | debug_vm86: |
574 | handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); | 669 | handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); |
575 | preempt_conditional_cli(regs); | 670 | preempt_conditional_cli(regs); |
576 | return; | 671 | return; |
672 | #endif | ||
577 | 673 | ||
578 | clear_TF_reenable: | 674 | clear_TF_reenable: |
579 | set_tsk_thread_flag(tsk, TIF_SINGLESTEP); | 675 | set_tsk_thread_flag(tsk, TIF_SINGLESTEP); |
@@ -582,6 +678,20 @@ clear_TF_reenable: | |||
582 | return; | 678 | return; |
583 | } | 679 | } |
584 | 680 | ||
681 | #ifdef CONFIG_X86_64 | ||
682 | static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) | ||
683 | { | ||
684 | if (fixup_exception(regs)) | ||
685 | return 1; | ||
686 | |||
687 | notify_die(DIE_GPF, str, regs, 0, trapnr, SIGFPE); | ||
688 | /* Illegal floating point operation in the kernel */ | ||
689 | current->thread.trap_no = trapnr; | ||
690 | die(str, regs, 0); | ||
691 | return 0; | ||
692 | } | ||
693 | #endif | ||
694 | |||
585 | /* | 695 | /* |
586 | * Note that we play around with the 'TS' bit in an attempt to get | 696 | * Note that we play around with the 'TS' bit in an attempt to get |
587 | * the correct behaviour even in the presence of the asynchronous | 697 | * the correct behaviour even in the presence of the asynchronous |
@@ -618,7 +728,9 @@ void math_error(void __user *ip) | |||
618 | swd = get_fpu_swd(task); | 728 | swd = get_fpu_swd(task); |
619 | switch (swd & ~cwd & 0x3f) { | 729 | switch (swd & ~cwd & 0x3f) { |
620 | case 0x000: /* No unmasked exception */ | 730 | case 0x000: /* No unmasked exception */ |
731 | #ifdef CONFIG_X86_32 | ||
621 | return; | 732 | return; |
733 | #endif | ||
622 | default: /* Multiple exceptions */ | 734 | default: /* Multiple exceptions */ |
623 | break; | 735 | break; |
624 | case 0x001: /* Invalid Op */ | 736 | case 0x001: /* Invalid Op */ |
@@ -649,7 +761,15 @@ void math_error(void __user *ip) | |||
649 | dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) | 761 | dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) |
650 | { | 762 | { |
651 | conditional_sti(regs); | 763 | conditional_sti(regs); |
764 | |||
765 | #ifdef CONFIG_X86_32 | ||
652 | ignore_fpu_irq = 1; | 766 | ignore_fpu_irq = 1; |
767 | #else | ||
768 | if (!user_mode(regs) && | ||
769 | kernel_math_error(regs, "kernel x87 math error", 16)) | ||
770 | return; | ||
771 | #endif | ||
772 | |||
653 | math_error((void __user *)regs->ip); | 773 | math_error((void __user *)regs->ip); |
654 | } | 774 | } |
655 | 775 | ||
@@ -706,6 +826,7 @@ do_simd_coprocessor_error(struct pt_regs *regs, long error_code) | |||
706 | { | 826 | { |
707 | conditional_sti(regs); | 827 | conditional_sti(regs); |
708 | 828 | ||
829 | #ifdef CONFIG_X86_32 | ||
709 | if (cpu_has_xmm) { | 830 | if (cpu_has_xmm) { |
710 | /* Handle SIMD FPU exceptions on PIII+ processors. */ | 831 | /* Handle SIMD FPU exceptions on PIII+ processors. */ |
711 | ignore_fpu_irq = 1; | 832 | ignore_fpu_irq = 1; |
@@ -724,6 +845,12 @@ do_simd_coprocessor_error(struct pt_regs *regs, long error_code) | |||
724 | current->thread.error_code = error_code; | 845 | current->thread.error_code = error_code; |
725 | die_if_kernel("cache flush denied", regs, error_code); | 846 | die_if_kernel("cache flush denied", regs, error_code); |
726 | force_sig(SIGSEGV, current); | 847 | force_sig(SIGSEGV, current); |
848 | #else | ||
849 | if (!user_mode(regs) && | ||
850 | kernel_math_error(regs, "kernel simd math error", 19)) | ||
851 | return; | ||
852 | simd_math_error((void __user *)regs->ip); | ||
853 | #endif | ||
727 | } | 854 | } |
728 | 855 | ||
729 | dotraplinkage void | 856 | dotraplinkage void |
@@ -736,6 +863,7 @@ do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) | |||
736 | #endif | 863 | #endif |
737 | } | 864 | } |
738 | 865 | ||
866 | #ifdef CONFIG_X86_32 | ||
739 | unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) | 867 | unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) |
740 | { | 868 | { |
741 | struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id()); | 869 | struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id()); |
@@ -754,6 +882,15 @@ unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) | |||
754 | 882 | ||
755 | return new_kesp; | 883 | return new_kesp; |
756 | } | 884 | } |
885 | #else | ||
886 | asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) | ||
887 | { | ||
888 | } | ||
889 | |||
890 | asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void) | ||
891 | { | ||
892 | } | ||
893 | #endif | ||
757 | 894 | ||
758 | /* | 895 | /* |
759 | * 'math_state_restore()' saves the current math information in the | 896 | * 'math_state_restore()' saves the current math information in the |
@@ -786,14 +923,24 @@ asmlinkage void math_state_restore(void) | |||
786 | } | 923 | } |
787 | 924 | ||
788 | clts(); /* Allow maths ops (or we recurse) */ | 925 | clts(); /* Allow maths ops (or we recurse) */ |
926 | #ifdef CONFIG_X86_32 | ||
789 | restore_fpu(tsk); | 927 | restore_fpu(tsk); |
928 | #else | ||
929 | /* | ||
930 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. | ||
931 | */ | ||
932 | if (unlikely(restore_fpu_checking(tsk))) { | ||
933 | stts(); | ||
934 | force_sig(SIGSEGV, tsk); | ||
935 | return; | ||
936 | } | ||
937 | #endif | ||
790 | thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ | 938 | thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ |
791 | tsk->fpu_counter++; | 939 | tsk->fpu_counter++; |
792 | } | 940 | } |
793 | EXPORT_SYMBOL_GPL(math_state_restore); | 941 | EXPORT_SYMBOL_GPL(math_state_restore); |
794 | 942 | ||
795 | #ifndef CONFIG_MATH_EMULATION | 943 | #ifndef CONFIG_MATH_EMULATION |
796 | |||
797 | asmlinkage void math_emulate(long arg) | 944 | asmlinkage void math_emulate(long arg) |
798 | { | 945 | { |
799 | printk(KERN_EMERG | 946 | printk(KERN_EMERG |
@@ -802,12 +949,12 @@ asmlinkage void math_emulate(long arg) | |||
802 | force_sig(SIGFPE, current); | 949 | force_sig(SIGFPE, current); |
803 | schedule(); | 950 | schedule(); |
804 | } | 951 | } |
805 | |||
806 | #endif /* CONFIG_MATH_EMULATION */ | 952 | #endif /* CONFIG_MATH_EMULATION */ |
807 | 953 | ||
808 | dotraplinkage void __kprobes | 954 | dotraplinkage void __kprobes |
809 | do_device_not_available(struct pt_regs *regs, long error) | 955 | do_device_not_available(struct pt_regs *regs, long error) |
810 | { | 956 | { |
957 | #ifdef CONFIG_X86_32 | ||
811 | if (read_cr0() & X86_CR0_EM) { | 958 | if (read_cr0() & X86_CR0_EM) { |
812 | conditional_sti(regs); | 959 | conditional_sti(regs); |
813 | math_emulate(0); | 960 | math_emulate(0); |
@@ -815,8 +962,12 @@ do_device_not_available(struct pt_regs *regs, long error) | |||
815 | math_state_restore(); /* interrupts still off */ | 962 | math_state_restore(); /* interrupts still off */ |
816 | conditional_sti(regs); | 963 | conditional_sti(regs); |
817 | } | 964 | } |
965 | #else | ||
966 | math_state_restore(); | ||
967 | #endif | ||
818 | } | 968 | } |
819 | 969 | ||
970 | #ifdef CONFIG_X86_32 | ||
820 | #ifdef CONFIG_X86_MCE | 971 | #ifdef CONFIG_X86_MCE |
821 | dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error) | 972 | dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error) |
822 | { | 973 | { |
@@ -839,10 +990,13 @@ dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) | |||
839 | return; | 990 | return; |
840 | do_trap(32, SIGILL, "iret exception", regs, error_code, &info); | 991 | do_trap(32, SIGILL, "iret exception", regs, error_code, &info); |
841 | } | 992 | } |
993 | #endif | ||
842 | 994 | ||
843 | void __init trap_init(void) | 995 | void __init trap_init(void) |
844 | { | 996 | { |
997 | #ifdef CONFIG_X86_32 | ||
845 | int i; | 998 | int i; |
999 | #endif | ||
846 | 1000 | ||
847 | #ifdef CONFIG_EISA | 1001 | #ifdef CONFIG_EISA |
848 | void __iomem *p = early_ioremap(0x0FFFD9, 4); | 1002 | void __iomem *p = early_ioremap(0x0FFFD9, 4); |
@@ -862,7 +1016,11 @@ void __init trap_init(void) | |||
862 | set_intr_gate(5, &bounds); | 1016 | set_intr_gate(5, &bounds); |
863 | set_intr_gate(6, &invalid_op); | 1017 | set_intr_gate(6, &invalid_op); |
864 | set_intr_gate(7, &device_not_available); | 1018 | set_intr_gate(7, &device_not_available); |
1019 | #ifdef CONFIG_X86_32 | ||
865 | set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS); | 1020 | set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS); |
1021 | #else | ||
1022 | set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK); | ||
1023 | #endif | ||
866 | set_intr_gate(9, &coprocessor_segment_overrun); | 1024 | set_intr_gate(9, &coprocessor_segment_overrun); |
867 | set_intr_gate(10, &invalid_TSS); | 1025 | set_intr_gate(10, &invalid_TSS); |
868 | set_intr_gate(11, &segment_not_present); | 1026 | set_intr_gate(11, &segment_not_present); |
@@ -877,6 +1035,11 @@ void __init trap_init(void) | |||
877 | #endif | 1035 | #endif |
878 | set_intr_gate(19, &simd_coprocessor_error); | 1036 | set_intr_gate(19, &simd_coprocessor_error); |
879 | 1037 | ||
1038 | #ifdef CONFIG_IA32_EMULATION | ||
1039 | set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall); | ||
1040 | #endif | ||
1041 | |||
1042 | #ifdef CONFIG_X86_32 | ||
880 | if (cpu_has_fxsr) { | 1043 | if (cpu_has_fxsr) { |
881 | printk(KERN_INFO "Enabling fast FPU save and restore... "); | 1044 | printk(KERN_INFO "Enabling fast FPU save and restore... "); |
882 | set_in_cr4(X86_CR4_OSFXSR); | 1045 | set_in_cr4(X86_CR4_OSFXSR); |
@@ -896,11 +1059,13 @@ void __init trap_init(void) | |||
896 | set_bit(i, used_vectors); | 1059 | set_bit(i, used_vectors); |
897 | 1060 | ||
898 | set_bit(SYSCALL_VECTOR, used_vectors); | 1061 | set_bit(SYSCALL_VECTOR, used_vectors); |
899 | 1062 | #endif | |
900 | /* | 1063 | /* |
901 | * Should be a barrier for any external CPU state: | 1064 | * Should be a barrier for any external CPU state: |
902 | */ | 1065 | */ |
903 | cpu_init(); | 1066 | cpu_init(); |
904 | 1067 | ||
1068 | #ifdef CONFIG_X86_32 | ||
905 | trap_init_hook(); | 1069 | trap_init_hook(); |
1070 | #endif | ||
906 | } | 1071 | } |
diff --git a/arch/x86/kernel/traps_64.c b/arch/x86/kernel/traps_64.c index 22fe62a24edb..60ecc855ab81 100644 --- a/arch/x86/kernel/traps_64.c +++ b/arch/x86/kernel/traps_64.c | |||
@@ -33,13 +33,21 @@ | |||
33 | #include <linux/smp.h> | 33 | #include <linux/smp.h> |
34 | #include <linux/io.h> | 34 | #include <linux/io.h> |
35 | 35 | ||
36 | #ifdef CONFIG_EISA | ||
37 | #include <linux/ioport.h> | ||
38 | #include <linux/eisa.h> | ||
39 | #endif | ||
40 | |||
41 | #ifdef CONFIG_MCA | ||
42 | #include <linux/mca.h> | ||
43 | #endif | ||
44 | |||
36 | #if defined(CONFIG_EDAC) | 45 | #if defined(CONFIG_EDAC) |
37 | #include <linux/edac.h> | 46 | #include <linux/edac.h> |
38 | #endif | 47 | #endif |
39 | 48 | ||
40 | #include <asm/stacktrace.h> | 49 | #include <asm/stacktrace.h> |
41 | #include <asm/processor.h> | 50 | #include <asm/processor.h> |
42 | #include <asm/kmemcheck.h> | ||
43 | #include <asm/debugreg.h> | 51 | #include <asm/debugreg.h> |
44 | #include <asm/atomic.h> | 52 | #include <asm/atomic.h> |
45 | #include <asm/system.h> | 53 | #include <asm/system.h> |
@@ -50,10 +58,35 @@ | |||
50 | 58 | ||
51 | #include <mach_traps.h> | 59 | #include <mach_traps.h> |
52 | 60 | ||
61 | #ifdef CONFIG_X86_64 | ||
53 | #include <asm/pgalloc.h> | 62 | #include <asm/pgalloc.h> |
54 | #include <asm/proto.h> | 63 | #include <asm/proto.h> |
55 | #include <asm/pda.h> | 64 | #include <asm/pda.h> |
65 | #else | ||
66 | #include <asm/processor-flags.h> | ||
67 | #include <asm/arch_hooks.h> | ||
68 | #include <asm/nmi.h> | ||
69 | #include <asm/smp.h> | ||
70 | #include <asm/io.h> | ||
71 | |||
72 | #include "cpu/mcheck/mce.h" | ||
56 | 73 | ||
74 | DECLARE_BITMAP(used_vectors, NR_VECTORS); | ||
75 | EXPORT_SYMBOL_GPL(used_vectors); | ||
76 | |||
77 | asmlinkage int system_call(void); | ||
78 | |||
79 | /* Do we ignore FPU interrupts ? */ | ||
80 | char ignore_fpu_irq; | ||
81 | |||
82 | /* | ||
83 | * The IDT has to be page-aligned to simplify the Pentium | ||
84 | * F0 0F bug workaround.. We have a special link segment | ||
85 | * for this. | ||
86 | */ | ||
87 | gate_desc idt_table[256] | ||
88 | __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; | ||
89 | #endif | ||
57 | 90 | ||
58 | static int ignore_nmis; | 91 | static int ignore_nmis; |
59 | 92 | ||
@@ -77,15 +110,80 @@ static inline void preempt_conditional_cli(struct pt_regs *regs) | |||
77 | dec_preempt_count(); | 110 | dec_preempt_count(); |
78 | } | 111 | } |
79 | 112 | ||
113 | #ifdef CONFIG_X86_32 | ||
114 | static inline void | ||
115 | die_if_kernel(const char *str, struct pt_regs *regs, long err) | ||
116 | { | ||
117 | if (!user_mode_vm(regs)) | ||
118 | die(str, regs, err); | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * Perform the lazy TSS's I/O bitmap copy. If the TSS has an | ||
123 | * invalid offset set (the LAZY one) and the faulting thread has | ||
124 | * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS, | ||
125 | * we set the offset field correctly and return 1. | ||
126 | */ | ||
127 | static int lazy_iobitmap_copy(void) | ||
128 | { | ||
129 | struct thread_struct *thread; | ||
130 | struct tss_struct *tss; | ||
131 | int cpu; | ||
132 | |||
133 | cpu = get_cpu(); | ||
134 | tss = &per_cpu(init_tss, cpu); | ||
135 | thread = ¤t->thread; | ||
136 | |||
137 | if (tss->x86_tss.io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && | ||
138 | thread->io_bitmap_ptr) { | ||
139 | memcpy(tss->io_bitmap, thread->io_bitmap_ptr, | ||
140 | thread->io_bitmap_max); | ||
141 | /* | ||
142 | * If the previously set map was extending to higher ports | ||
143 | * than the current one, pad extra space with 0xff (no access). | ||
144 | */ | ||
145 | if (thread->io_bitmap_max < tss->io_bitmap_max) { | ||
146 | memset((char *) tss->io_bitmap + | ||
147 | thread->io_bitmap_max, 0xff, | ||
148 | tss->io_bitmap_max - thread->io_bitmap_max); | ||
149 | } | ||
150 | tss->io_bitmap_max = thread->io_bitmap_max; | ||
151 | tss->x86_tss.io_bitmap_base = IO_BITMAP_OFFSET; | ||
152 | tss->io_bitmap_owner = thread; | ||
153 | put_cpu(); | ||
154 | |||
155 | return 1; | ||
156 | } | ||
157 | put_cpu(); | ||
158 | |||
159 | return 0; | ||
160 | } | ||
161 | #endif | ||
162 | |||
80 | static void __kprobes | 163 | static void __kprobes |
81 | do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, | 164 | do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, |
82 | long error_code, siginfo_t *info) | 165 | long error_code, siginfo_t *info) |
83 | { | 166 | { |
84 | struct task_struct *tsk = current; | 167 | struct task_struct *tsk = current; |
85 | 168 | ||
169 | #ifdef CONFIG_X86_32 | ||
170 | if (regs->flags & X86_VM_MASK) { | ||
171 | /* | ||
172 | * traps 0, 1, 3, 4, and 5 should be forwarded to vm86. | ||
173 | * On nmi (interrupt 2), do_trap should not be called. | ||
174 | */ | ||
175 | if (trapnr < 6) | ||
176 | goto vm86_trap; | ||
177 | goto trap_signal; | ||
178 | } | ||
179 | #endif | ||
180 | |||
86 | if (!user_mode(regs)) | 181 | if (!user_mode(regs)) |
87 | goto kernel_trap; | 182 | goto kernel_trap; |
88 | 183 | ||
184 | #ifdef CONFIG_X86_32 | ||
185 | trap_signal: | ||
186 | #endif | ||
89 | /* | 187 | /* |
90 | * We want error_code and trap_no set for userspace faults and | 188 | * We want error_code and trap_no set for userspace faults and |
91 | * kernelspace faults which result in die(), but not | 189 | * kernelspace faults which result in die(), but not |
@@ -98,6 +196,7 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, | |||
98 | tsk->thread.error_code = error_code; | 196 | tsk->thread.error_code = error_code; |
99 | tsk->thread.trap_no = trapnr; | 197 | tsk->thread.trap_no = trapnr; |
100 | 198 | ||
199 | #ifdef CONFIG_X86_64 | ||
101 | if (show_unhandled_signals && unhandled_signal(tsk, signr) && | 200 | if (show_unhandled_signals && unhandled_signal(tsk, signr) && |
102 | printk_ratelimit()) { | 201 | printk_ratelimit()) { |
103 | printk(KERN_INFO | 202 | printk(KERN_INFO |
@@ -107,6 +206,7 @@ do_trap(int trapnr, int signr, char *str, struct pt_regs *regs, | |||
107 | print_vma_addr(" in ", regs->ip); | 206 | print_vma_addr(" in ", regs->ip); |
108 | printk("\n"); | 207 | printk("\n"); |
109 | } | 208 | } |
209 | #endif | ||
110 | 210 | ||
111 | if (info) | 211 | if (info) |
112 | force_sig_info(signr, info, tsk); | 212 | force_sig_info(signr, info, tsk); |
@@ -121,6 +221,14 @@ kernel_trap: | |||
121 | die(str, regs, error_code); | 221 | die(str, regs, error_code); |
122 | } | 222 | } |
123 | return; | 223 | return; |
224 | |||
225 | #ifdef CONFIG_X86_32 | ||
226 | vm86_trap: | ||
227 | if (handle_vm86_trap((struct kernel_vm86_regs *) regs, | ||
228 | error_code, trapnr)) | ||
229 | goto trap_signal; | ||
230 | return; | ||
231 | #endif | ||
124 | } | 232 | } |
125 | 233 | ||
126 | #define DO_ERROR(trapnr, signr, str, name) \ | 234 | #define DO_ERROR(trapnr, signr, str, name) \ |
@@ -155,8 +263,12 @@ DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip) | |||
155 | DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) | 263 | DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) |
156 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) | 264 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) |
157 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) | 265 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) |
266 | #ifdef CONFIG_X86_32 | ||
267 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) | ||
268 | #endif | ||
158 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) | 269 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) |
159 | 270 | ||
271 | #ifdef CONFIG_X86_64 | ||
160 | /* Runs on IST stack */ | 272 | /* Runs on IST stack */ |
161 | dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) | 273 | dotraplinkage void do_stack_segment(struct pt_regs *regs, long error_code) |
162 | { | 274 | { |
@@ -184,6 +296,7 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code) | |||
184 | for (;;) | 296 | for (;;) |
185 | die(str, regs, error_code); | 297 | die(str, regs, error_code); |
186 | } | 298 | } |
299 | #endif | ||
187 | 300 | ||
188 | dotraplinkage void __kprobes | 301 | dotraplinkage void __kprobes |
189 | do_general_protection(struct pt_regs *regs, long error_code) | 302 | do_general_protection(struct pt_regs *regs, long error_code) |
@@ -192,6 +305,16 @@ do_general_protection(struct pt_regs *regs, long error_code) | |||
192 | 305 | ||
193 | conditional_sti(regs); | 306 | conditional_sti(regs); |
194 | 307 | ||
308 | #ifdef CONFIG_X86_32 | ||
309 | if (lazy_iobitmap_copy()) { | ||
310 | /* restart the faulting instruction */ | ||
311 | return; | ||
312 | } | ||
313 | |||
314 | if (regs->flags & X86_VM_MASK) | ||
315 | goto gp_in_vm86; | ||
316 | #endif | ||
317 | |||
195 | tsk = current; | 318 | tsk = current; |
196 | if (!user_mode(regs)) | 319 | if (!user_mode(regs)) |
197 | goto gp_in_kernel; | 320 | goto gp_in_kernel; |
@@ -212,6 +335,13 @@ do_general_protection(struct pt_regs *regs, long error_code) | |||
212 | force_sig(SIGSEGV, tsk); | 335 | force_sig(SIGSEGV, tsk); |
213 | return; | 336 | return; |
214 | 337 | ||
338 | #ifdef CONFIG_X86_32 | ||
339 | gp_in_vm86: | ||
340 | local_irq_enable(); | ||
341 | handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); | ||
342 | return; | ||
343 | #endif | ||
344 | |||
215 | gp_in_kernel: | 345 | gp_in_kernel: |
216 | if (fixup_exception(regs)) | 346 | if (fixup_exception(regs)) |
217 | return; | 347 | return; |
@@ -277,6 +407,16 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs) | |||
277 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == | 407 | if (notify_die(DIE_NMIUNKNOWN, "nmi", regs, reason, 2, SIGINT) == |
278 | NOTIFY_STOP) | 408 | NOTIFY_STOP) |
279 | return; | 409 | return; |
410 | #ifdef CONFIG_MCA | ||
411 | /* | ||
412 | * Might actually be able to figure out what the guilty party | ||
413 | * is: | ||
414 | */ | ||
415 | if (MCA_bus) { | ||
416 | mca_handle_nmi(); | ||
417 | return; | ||
418 | } | ||
419 | #endif | ||
280 | printk(KERN_EMERG | 420 | printk(KERN_EMERG |
281 | "Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", | 421 | "Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", |
282 | reason, smp_processor_id()); | 422 | reason, smp_processor_id()); |
@@ -288,6 +428,43 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs) | |||
288 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); | 428 | printk(KERN_EMERG "Dazed and confused, but trying to continue\n"); |
289 | } | 429 | } |
290 | 430 | ||
431 | #ifdef CONFIG_X86_32 | ||
432 | static DEFINE_SPINLOCK(nmi_print_lock); | ||
433 | |||
434 | void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) | ||
435 | { | ||
436 | if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) | ||
437 | return; | ||
438 | |||
439 | spin_lock(&nmi_print_lock); | ||
440 | /* | ||
441 | * We are in trouble anyway, lets at least try | ||
442 | * to get a message out: | ||
443 | */ | ||
444 | bust_spinlocks(1); | ||
445 | printk(KERN_EMERG "%s", str); | ||
446 | printk(" on CPU%d, ip %08lx, registers:\n", | ||
447 | smp_processor_id(), regs->ip); | ||
448 | show_registers(regs); | ||
449 | if (do_panic) | ||
450 | panic("Non maskable interrupt"); | ||
451 | console_silent(); | ||
452 | spin_unlock(&nmi_print_lock); | ||
453 | bust_spinlocks(0); | ||
454 | |||
455 | /* | ||
456 | * If we are in kernel we are probably nested up pretty bad | ||
457 | * and might aswell get out now while we still can: | ||
458 | */ | ||
459 | if (!user_mode_vm(regs)) { | ||
460 | current->thread.trap_no = 2; | ||
461 | crash_kexec(regs); | ||
462 | } | ||
463 | |||
464 | do_exit(SIGSEGV); | ||
465 | } | ||
466 | #endif | ||
467 | |||
291 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | 468 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) |
292 | { | 469 | { |
293 | unsigned char reason = 0; | 470 | unsigned char reason = 0; |
@@ -303,6 +480,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | |||
303 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) | 480 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) |
304 | == NOTIFY_STOP) | 481 | == NOTIFY_STOP) |
305 | return; | 482 | return; |
483 | #ifdef CONFIG_X86_LOCAL_APIC | ||
306 | /* | 484 | /* |
307 | * Ok, so this is none of the documented NMI sources, | 485 | * Ok, so this is none of the documented NMI sources, |
308 | * so it must be the NMI watchdog. | 486 | * so it must be the NMI watchdog. |
@@ -311,6 +489,9 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | |||
311 | return; | 489 | return; |
312 | if (!do_nmi_callback(regs, cpu)) | 490 | if (!do_nmi_callback(regs, cpu)) |
313 | unknown_nmi_error(reason, regs); | 491 | unknown_nmi_error(reason, regs); |
492 | #else | ||
493 | unknown_nmi_error(reason, regs); | ||
494 | #endif | ||
314 | 495 | ||
315 | return; | 496 | return; |
316 | } | 497 | } |
@@ -322,6 +503,13 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | |||
322 | mem_parity_error(reason, regs); | 503 | mem_parity_error(reason, regs); |
323 | if (reason & 0x40) | 504 | if (reason & 0x40) |
324 | io_check_error(reason, regs); | 505 | io_check_error(reason, regs); |
506 | #ifdef CONFIG_X86_32 | ||
507 | /* | ||
508 | * Reassert NMI in case it became active meanwhile | ||
509 | * as it's edge-triggered: | ||
510 | */ | ||
511 | reassert_nmi(); | ||
512 | #endif | ||
325 | } | 513 | } |
326 | 514 | ||
327 | dotraplinkage notrace __kprobes void | 515 | dotraplinkage notrace __kprobes void |
@@ -329,7 +517,11 @@ do_nmi(struct pt_regs *regs, long error_code) | |||
329 | { | 517 | { |
330 | nmi_enter(); | 518 | nmi_enter(); |
331 | 519 | ||
520 | #ifdef CONFIG_X86_32 | ||
521 | { int cpu; cpu = smp_processor_id(); ++nmi_count(cpu); } | ||
522 | #else | ||
332 | add_pda(__nmi_count, 1); | 523 | add_pda(__nmi_count, 1); |
524 | #endif | ||
333 | 525 | ||
334 | if (!ignore_nmis) | 526 | if (!ignore_nmis) |
335 | default_do_nmi(regs); | 527 | default_do_nmi(regs); |
@@ -352,15 +544,22 @@ void restart_nmi(void) | |||
352 | /* May run on IST stack. */ | 544 | /* May run on IST stack. */ |
353 | dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) | 545 | dotraplinkage void __kprobes do_int3(struct pt_regs *regs, long error_code) |
354 | { | 546 | { |
547 | #ifdef CONFIG_KPROBES | ||
355 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) | 548 | if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) |
356 | == NOTIFY_STOP) | 549 | == NOTIFY_STOP) |
357 | return; | 550 | return; |
551 | #else | ||
552 | if (notify_die(DIE_TRAP, "int3", regs, error_code, 3, SIGTRAP) | ||
553 | == NOTIFY_STOP) | ||
554 | return; | ||
555 | #endif | ||
358 | 556 | ||
359 | preempt_conditional_sti(regs); | 557 | preempt_conditional_sti(regs); |
360 | do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); | 558 | do_trap(3, SIGTRAP, "int3", regs, error_code, NULL); |
361 | preempt_conditional_cli(regs); | 559 | preempt_conditional_cli(regs); |
362 | } | 560 | } |
363 | 561 | ||
562 | #ifdef CONFIG_X86_64 | ||
364 | /* Help handler running on IST stack to switch back to user stack | 563 | /* Help handler running on IST stack to switch back to user stack |
365 | for scheduling or signal handling. The actual stack switch is done in | 564 | for scheduling or signal handling. The actual stack switch is done in |
366 | entry.S */ | 565 | entry.S */ |
@@ -381,6 +580,7 @@ asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs) | |||
381 | *regs = *eregs; | 580 | *regs = *eregs; |
382 | return regs; | 581 | return regs; |
383 | } | 582 | } |
583 | #endif | ||
384 | 584 | ||
385 | /* | 585 | /* |
386 | * Our handling of the processor debug registers is non-trivial. | 586 | * Our handling of the processor debug registers is non-trivial. |
@@ -433,6 +633,11 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
433 | goto clear_dr7; | 633 | goto clear_dr7; |
434 | } | 634 | } |
435 | 635 | ||
636 | #ifdef CONFIG_X86_32 | ||
637 | if (regs->flags & X86_VM_MASK) | ||
638 | goto debug_vm86; | ||
639 | #endif | ||
640 | |||
436 | /* Save debug status register where ptrace can see it */ | 641 | /* Save debug status register where ptrace can see it */ |
437 | tsk->thread.debugreg6 = condition; | 642 | tsk->thread.debugreg6 = condition; |
438 | 643 | ||
@@ -458,6 +663,13 @@ clear_dr7: | |||
458 | preempt_conditional_cli(regs); | 663 | preempt_conditional_cli(regs); |
459 | return; | 664 | return; |
460 | 665 | ||
666 | #ifdef CONFIG_X86_32 | ||
667 | debug_vm86: | ||
668 | handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); | ||
669 | preempt_conditional_cli(regs); | ||
670 | return; | ||
671 | #endif | ||
672 | |||
461 | clear_TF_reenable: | 673 | clear_TF_reenable: |
462 | set_tsk_thread_flag(tsk, TIF_SINGLESTEP); | 674 | set_tsk_thread_flag(tsk, TIF_SINGLESTEP); |
463 | regs->flags &= ~X86_EFLAGS_TF; | 675 | regs->flags &= ~X86_EFLAGS_TF; |
@@ -465,6 +677,7 @@ clear_TF_reenable: | |||
465 | return; | 677 | return; |
466 | } | 678 | } |
467 | 679 | ||
680 | #ifdef CONFIG_X86_64 | ||
468 | static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) | 681 | static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) |
469 | { | 682 | { |
470 | if (fixup_exception(regs)) | 683 | if (fixup_exception(regs)) |
@@ -476,6 +689,7 @@ static int kernel_math_error(struct pt_regs *regs, const char *str, int trapnr) | |||
476 | die(str, regs, 0); | 689 | die(str, regs, 0); |
477 | return 0; | 690 | return 0; |
478 | } | 691 | } |
692 | #endif | ||
479 | 693 | ||
480 | /* | 694 | /* |
481 | * Note that we play around with the 'TS' bit in an attempt to get | 695 | * Note that we play around with the 'TS' bit in an attempt to get |
@@ -513,6 +727,9 @@ void math_error(void __user *ip) | |||
513 | swd = get_fpu_swd(task); | 727 | swd = get_fpu_swd(task); |
514 | switch (swd & ~cwd & 0x3f) { | 728 | switch (swd & ~cwd & 0x3f) { |
515 | case 0x000: /* No unmasked exception */ | 729 | case 0x000: /* No unmasked exception */ |
730 | #ifdef CONFIG_X86_32 | ||
731 | return; | ||
732 | #endif | ||
516 | default: /* Multiple exceptions */ | 733 | default: /* Multiple exceptions */ |
517 | break; | 734 | break; |
518 | case 0x001: /* Invalid Op */ | 735 | case 0x001: /* Invalid Op */ |
@@ -543,9 +760,15 @@ void math_error(void __user *ip) | |||
543 | dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) | 760 | dotraplinkage void do_coprocessor_error(struct pt_regs *regs, long error_code) |
544 | { | 761 | { |
545 | conditional_sti(regs); | 762 | conditional_sti(regs); |
763 | |||
764 | #ifdef CONFIG_X86_32 | ||
765 | ignore_fpu_irq = 1; | ||
766 | #else | ||
546 | if (!user_mode(regs) && | 767 | if (!user_mode(regs) && |
547 | kernel_math_error(regs, "kernel x87 math error", 16)) | 768 | kernel_math_error(regs, "kernel x87 math error", 16)) |
548 | return; | 769 | return; |
770 | #endif | ||
771 | |||
549 | math_error((void __user *)regs->ip); | 772 | math_error((void __user *)regs->ip); |
550 | } | 773 | } |
551 | 774 | ||
@@ -601,17 +824,64 @@ dotraplinkage void | |||
601 | do_simd_coprocessor_error(struct pt_regs *regs, long error_code) | 824 | do_simd_coprocessor_error(struct pt_regs *regs, long error_code) |
602 | { | 825 | { |
603 | conditional_sti(regs); | 826 | conditional_sti(regs); |
827 | |||
828 | #ifdef CONFIG_X86_32 | ||
829 | if (cpu_has_xmm) { | ||
830 | /* Handle SIMD FPU exceptions on PIII+ processors. */ | ||
831 | ignore_fpu_irq = 1; | ||
832 | simd_math_error((void __user *)regs->ip); | ||
833 | return; | ||
834 | } | ||
835 | /* | ||
836 | * Handle strange cache flush from user space exception | ||
837 | * in all other cases. This is undocumented behaviour. | ||
838 | */ | ||
839 | if (regs->flags & X86_VM_MASK) { | ||
840 | handle_vm86_fault((struct kernel_vm86_regs *)regs, error_code); | ||
841 | return; | ||
842 | } | ||
843 | current->thread.trap_no = 19; | ||
844 | current->thread.error_code = error_code; | ||
845 | die_if_kernel("cache flush denied", regs, error_code); | ||
846 | force_sig(SIGSEGV, current); | ||
847 | #else | ||
604 | if (!user_mode(regs) && | 848 | if (!user_mode(regs) && |
605 | kernel_math_error(regs, "kernel simd math error", 19)) | 849 | kernel_math_error(regs, "kernel simd math error", 19)) |
606 | return; | 850 | return; |
607 | simd_math_error((void __user *)regs->ip); | 851 | simd_math_error((void __user *)regs->ip); |
852 | #endif | ||
608 | } | 853 | } |
609 | 854 | ||
610 | dotraplinkage void | 855 | dotraplinkage void |
611 | do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) | 856 | do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) |
612 | { | 857 | { |
858 | conditional_sti(regs); | ||
859 | #if 0 | ||
860 | /* No need to warn about this any longer. */ | ||
861 | printk(KERN_INFO "Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); | ||
862 | #endif | ||
613 | } | 863 | } |
614 | 864 | ||
865 | #ifdef CONFIG_X86_32 | ||
866 | unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) | ||
867 | { | ||
868 | struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id()); | ||
869 | unsigned long base = (kesp - uesp) & -THREAD_SIZE; | ||
870 | unsigned long new_kesp = kesp - base; | ||
871 | unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; | ||
872 | __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS]; | ||
873 | |||
874 | /* Set up base for espfix segment */ | ||
875 | desc &= 0x00f0ff0000000000ULL; | ||
876 | desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) | | ||
877 | ((((__u64)base) << 32) & 0xff00000000000000ULL) | | ||
878 | ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) | | ||
879 | (lim_pages & 0xffff); | ||
880 | *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc; | ||
881 | |||
882 | return new_kesp; | ||
883 | } | ||
884 | #else | ||
615 | asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) | 885 | asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) |
616 | { | 886 | { |
617 | } | 887 | } |
@@ -619,6 +889,7 @@ asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void) | |||
619 | asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void) | 889 | asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void) |
620 | { | 890 | { |
621 | } | 891 | } |
892 | #endif | ||
622 | 893 | ||
623 | /* | 894 | /* |
624 | * 'math_state_restore()' saves the current math information in the | 895 | * 'math_state_restore()' saves the current math information in the |
@@ -626,6 +897,9 @@ asmlinkage void __attribute__((weak)) mce_threshold_interrupt(void) | |||
626 | * | 897 | * |
627 | * Careful.. There are problems with IBM-designed IRQ13 behaviour. | 898 | * Careful.. There are problems with IBM-designed IRQ13 behaviour. |
628 | * Don't touch unless you *really* know how it works. | 899 | * Don't touch unless you *really* know how it works. |
900 | * | ||
901 | * Must be called with kernel preemption disabled (in this case, | ||
902 | * local interrupts are disabled at the call-site in entry.S). | ||
629 | */ | 903 | */ |
630 | asmlinkage void math_state_restore(void) | 904 | asmlinkage void math_state_restore(void) |
631 | { | 905 | { |
@@ -648,6 +922,9 @@ asmlinkage void math_state_restore(void) | |||
648 | } | 922 | } |
649 | 923 | ||
650 | clts(); /* Allow maths ops (or we recurse) */ | 924 | clts(); /* Allow maths ops (or we recurse) */ |
925 | #ifdef CONFIG_X86_32 | ||
926 | restore_fpu(tsk); | ||
927 | #else | ||
651 | /* | 928 | /* |
652 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. | 929 | * Paranoid restore. send a SIGSEGV if we fail to restore the state. |
653 | */ | 930 | */ |
@@ -656,19 +933,78 @@ asmlinkage void math_state_restore(void) | |||
656 | force_sig(SIGSEGV, tsk); | 933 | force_sig(SIGSEGV, tsk); |
657 | return; | 934 | return; |
658 | } | 935 | } |
936 | #endif | ||
659 | thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ | 937 | thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ |
660 | tsk->fpu_counter++; | 938 | tsk->fpu_counter++; |
661 | } | 939 | } |
662 | EXPORT_SYMBOL_GPL(math_state_restore); | 940 | EXPORT_SYMBOL_GPL(math_state_restore); |
663 | 941 | ||
942 | #ifndef CONFIG_MATH_EMULATION | ||
943 | asmlinkage void math_emulate(long arg) | ||
944 | { | ||
945 | printk(KERN_EMERG | ||
946 | "math-emulation not enabled and no coprocessor found.\n"); | ||
947 | printk(KERN_EMERG "killing %s.\n", current->comm); | ||
948 | force_sig(SIGFPE, current); | ||
949 | schedule(); | ||
950 | } | ||
951 | #endif /* CONFIG_MATH_EMULATION */ | ||
952 | |||
664 | dotraplinkage void __kprobes | 953 | dotraplinkage void __kprobes |
665 | do_device_not_available(struct pt_regs *regs, long error) | 954 | do_device_not_available(struct pt_regs *regs, long error) |
666 | { | 955 | { |
956 | #ifdef CONFIG_X86_32 | ||
957 | if (read_cr0() & X86_CR0_EM) { | ||
958 | conditional_sti(regs); | ||
959 | math_emulate(0); | ||
960 | } else { | ||
961 | math_state_restore(); /* interrupts still off */ | ||
962 | conditional_sti(regs); | ||
963 | } | ||
964 | #else | ||
667 | math_state_restore(); | 965 | math_state_restore(); |
966 | #endif | ||
967 | } | ||
968 | |||
969 | #ifdef CONFIG_X86_32 | ||
970 | #ifdef CONFIG_X86_MCE | ||
971 | dotraplinkage void __kprobes do_machine_check(struct pt_regs *regs, long error) | ||
972 | { | ||
973 | conditional_sti(regs); | ||
974 | machine_check_vector(regs, error); | ||
668 | } | 975 | } |
976 | #endif | ||
977 | |||
978 | dotraplinkage void do_iret_error(struct pt_regs *regs, long error_code) | ||
979 | { | ||
980 | siginfo_t info; | ||
981 | local_irq_enable(); | ||
982 | |||
983 | info.si_signo = SIGILL; | ||
984 | info.si_errno = 0; | ||
985 | info.si_code = ILL_BADSTK; | ||
986 | info.si_addr = 0; | ||
987 | if (notify_die(DIE_TRAP, "iret exception", | ||
988 | regs, error_code, 32, SIGILL) == NOTIFY_STOP) | ||
989 | return; | ||
990 | do_trap(32, SIGILL, "iret exception", regs, error_code, &info); | ||
991 | } | ||
992 | #endif | ||
669 | 993 | ||
670 | void __init trap_init(void) | 994 | void __init trap_init(void) |
671 | { | 995 | { |
996 | #ifdef CONFIG_X86_32 | ||
997 | int i; | ||
998 | #endif | ||
999 | |||
1000 | #ifdef CONFIG_EISA | ||
1001 | void __iomem *p = early_ioremap(0x0FFFD9, 4); | ||
1002 | |||
1003 | if (readl(p) == 'E' + ('I'<<8) + ('S'<<16) + ('A'<<24)) | ||
1004 | EISA_bus = 1; | ||
1005 | early_iounmap(p, 4); | ||
1006 | #endif | ||
1007 | |||
672 | set_intr_gate(0, ÷_error); | 1008 | set_intr_gate(0, ÷_error); |
673 | set_intr_gate_ist(1, &debug, DEBUG_STACK); | 1009 | set_intr_gate_ist(1, &debug, DEBUG_STACK); |
674 | set_intr_gate_ist(2, &nmi, NMI_STACK); | 1010 | set_intr_gate_ist(2, &nmi, NMI_STACK); |
@@ -679,7 +1015,11 @@ void __init trap_init(void) | |||
679 | set_intr_gate(5, &bounds); | 1015 | set_intr_gate(5, &bounds); |
680 | set_intr_gate(6, &invalid_op); | 1016 | set_intr_gate(6, &invalid_op); |
681 | set_intr_gate(7, &device_not_available); | 1017 | set_intr_gate(7, &device_not_available); |
1018 | #ifdef CONFIG_X86_32 | ||
1019 | set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS); | ||
1020 | #else | ||
682 | set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK); | 1021 | set_intr_gate_ist(8, &double_fault, DOUBLEFAULT_STACK); |
1022 | #endif | ||
683 | set_intr_gate(9, &coprocessor_segment_overrun); | 1023 | set_intr_gate(9, &coprocessor_segment_overrun); |
684 | set_intr_gate(10, &invalid_TSS); | 1024 | set_intr_gate(10, &invalid_TSS); |
685 | set_intr_gate(11, &segment_not_present); | 1025 | set_intr_gate(11, &segment_not_present); |
@@ -697,8 +1037,34 @@ void __init trap_init(void) | |||
697 | #ifdef CONFIG_IA32_EMULATION | 1037 | #ifdef CONFIG_IA32_EMULATION |
698 | set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall); | 1038 | set_system_intr_gate(IA32_SYSCALL_VECTOR, ia32_syscall); |
699 | #endif | 1039 | #endif |
1040 | |||
1041 | #ifdef CONFIG_X86_32 | ||
1042 | if (cpu_has_fxsr) { | ||
1043 | printk(KERN_INFO "Enabling fast FPU save and restore... "); | ||
1044 | set_in_cr4(X86_CR4_OSFXSR); | ||
1045 | printk("done.\n"); | ||
1046 | } | ||
1047 | if (cpu_has_xmm) { | ||
1048 | printk(KERN_INFO | ||
1049 | "Enabling unmasked SIMD FPU exception support... "); | ||
1050 | set_in_cr4(X86_CR4_OSXMMEXCPT); | ||
1051 | printk("done.\n"); | ||
1052 | } | ||
1053 | |||
1054 | set_system_trap_gate(SYSCALL_VECTOR, &system_call); | ||
1055 | |||
1056 | /* Reserve all the builtin and the syscall vector: */ | ||
1057 | for (i = 0; i < FIRST_EXTERNAL_VECTOR; i++) | ||
1058 | set_bit(i, used_vectors); | ||
1059 | |||
1060 | set_bit(SYSCALL_VECTOR, used_vectors); | ||
1061 | #endif | ||
700 | /* | 1062 | /* |
701 | * Should be a barrier for any external CPU state: | 1063 | * Should be a barrier for any external CPU state: |
702 | */ | 1064 | */ |
703 | cpu_init(); | 1065 | cpu_init(); |
1066 | |||
1067 | #ifdef CONFIG_X86_32 | ||
1068 | trap_init_hook(); | ||
1069 | #endif | ||
704 | } | 1070 | } |