diff options
Diffstat (limited to 'arch/x86/kernel/traps_32.c')
-rw-r--r-- | arch/x86/kernel/traps_32.c | 190 |
1 files changed, 94 insertions, 96 deletions
diff --git a/arch/x86/kernel/traps_32.c b/arch/x86/kernel/traps_32.c index 08d752de4eee..8a768973c4f0 100644 --- a/arch/x86/kernel/traps_32.c +++ b/arch/x86/kernel/traps_32.c | |||
@@ -1,5 +1,6 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 1991, 1992 Linus Torvalds | 2 | * Copyright (C) 1991, 1992 Linus Torvalds |
3 | * Copyright (C) 2000, 2001, 2002 Andi Kleen, SuSE Labs | ||
3 | * | 4 | * |
4 | * Pentium III FXSR, SSE support | 5 | * Pentium III FXSR, SSE support |
5 | * Gareth Hughes <gareth@valinux.com>, May 2000 | 6 | * Gareth Hughes <gareth@valinux.com>, May 2000 |
@@ -60,8 +61,6 @@ | |||
60 | 61 | ||
61 | #include "mach_traps.h" | 62 | #include "mach_traps.h" |
62 | 63 | ||
63 | int panic_on_unrecovered_nmi; | ||
64 | |||
65 | DECLARE_BITMAP(used_vectors, NR_VECTORS); | 64 | DECLARE_BITMAP(used_vectors, NR_VECTORS); |
66 | EXPORT_SYMBOL_GPL(used_vectors); | 65 | EXPORT_SYMBOL_GPL(used_vectors); |
67 | 66 | ||
@@ -98,19 +97,22 @@ asmlinkage void alignment_check(void); | |||
98 | asmlinkage void spurious_interrupt_bug(void); | 97 | asmlinkage void spurious_interrupt_bug(void); |
99 | asmlinkage void machine_check(void); | 98 | asmlinkage void machine_check(void); |
100 | 99 | ||
100 | int panic_on_unrecovered_nmi; | ||
101 | int kstack_depth_to_print = 24; | 101 | int kstack_depth_to_print = 24; |
102 | static unsigned int code_bytes = 64; | 102 | static unsigned int code_bytes = 64; |
103 | static int ignore_nmis; | ||
104 | static int die_counter; | ||
103 | 105 | ||
104 | void printk_address(unsigned long address, int reliable) | 106 | void printk_address(unsigned long address, int reliable) |
105 | { | 107 | { |
106 | #ifdef CONFIG_KALLSYMS | 108 | #ifdef CONFIG_KALLSYMS |
107 | char namebuf[KSYM_NAME_LEN]; | ||
108 | unsigned long offset = 0; | 109 | unsigned long offset = 0; |
109 | unsigned long symsize; | 110 | unsigned long symsize; |
110 | const char *symname; | 111 | const char *symname; |
111 | char reliab[4] = ""; | ||
112 | char *delim = ":"; | ||
113 | char *modname; | 112 | char *modname; |
113 | char *delim = ":"; | ||
114 | char namebuf[KSYM_NAME_LEN]; | ||
115 | char reliab[4] = ""; | ||
114 | 116 | ||
115 | symname = kallsyms_lookup(address, &symsize, &offset, | 117 | symname = kallsyms_lookup(address, &symsize, &offset, |
116 | &modname, namebuf); | 118 | &modname, namebuf); |
@@ -130,22 +132,23 @@ void printk_address(unsigned long address, int reliable) | |||
130 | #endif | 132 | #endif |
131 | } | 133 | } |
132 | 134 | ||
133 | static inline int valid_stack_ptr(struct thread_info *tinfo, void *p, unsigned size) | 135 | static inline int valid_stack_ptr(struct thread_info *tinfo, |
136 | void *p, unsigned int size) | ||
134 | { | 137 | { |
135 | return p > (void *)tinfo && | 138 | void *t = tinfo; |
136 | p <= (void *)tinfo + THREAD_SIZE - size; | 139 | return p > t && p <= t + THREAD_SIZE - size; |
137 | } | 140 | } |
138 | 141 | ||
139 | /* The form of the top of the frame on the stack */ | 142 | /* The form of the top of the frame on the stack */ |
140 | struct stack_frame { | 143 | struct stack_frame { |
141 | struct stack_frame *next_frame; | 144 | struct stack_frame *next_frame; |
142 | unsigned long return_address; | 145 | unsigned long return_address; |
143 | }; | 146 | }; |
144 | 147 | ||
145 | static inline unsigned long | 148 | static inline unsigned long |
146 | print_context_stack(struct thread_info *tinfo, | 149 | print_context_stack(struct thread_info *tinfo, |
147 | unsigned long *stack, unsigned long bp, | 150 | unsigned long *stack, unsigned long bp, |
148 | const struct stacktrace_ops *ops, void *data) | 151 | const struct stacktrace_ops *ops, void *data) |
149 | { | 152 | { |
150 | struct stack_frame *frame = (struct stack_frame *)bp; | 153 | struct stack_frame *frame = (struct stack_frame *)bp; |
151 | 154 | ||
@@ -167,8 +170,6 @@ print_context_stack(struct thread_info *tinfo, | |||
167 | return bp; | 170 | return bp; |
168 | } | 171 | } |
169 | 172 | ||
170 | #define MSG(msg) ops->warning(data, msg) | ||
171 | |||
172 | void dump_trace(struct task_struct *task, struct pt_regs *regs, | 173 | void dump_trace(struct task_struct *task, struct pt_regs *regs, |
173 | unsigned long *stack, unsigned long bp, | 174 | unsigned long *stack, unsigned long bp, |
174 | const struct stacktrace_ops *ops, void *data) | 175 | const struct stacktrace_ops *ops, void *data) |
@@ -178,7 +179,6 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
178 | 179 | ||
179 | if (!stack) { | 180 | if (!stack) { |
180 | unsigned long dummy; | 181 | unsigned long dummy; |
181 | |||
182 | stack = &dummy; | 182 | stack = &dummy; |
183 | if (task != current) | 183 | if (task != current) |
184 | stack = (unsigned long *)task->thread.sp; | 184 | stack = (unsigned long *)task->thread.sp; |
@@ -196,7 +196,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs, | |||
196 | } | 196 | } |
197 | #endif | 197 | #endif |
198 | 198 | ||
199 | while (1) { | 199 | for (;;) { |
200 | struct thread_info *context; | 200 | struct thread_info *context; |
201 | 201 | ||
202 | context = (struct thread_info *) | 202 | context = (struct thread_info *) |
@@ -248,10 +248,10 @@ static void print_trace_address(void *data, unsigned long addr, int reliable) | |||
248 | } | 248 | } |
249 | 249 | ||
250 | static const struct stacktrace_ops print_trace_ops = { | 250 | static const struct stacktrace_ops print_trace_ops = { |
251 | .warning = print_trace_warning, | 251 | .warning = print_trace_warning, |
252 | .warning_symbol = print_trace_warning_symbol, | 252 | .warning_symbol = print_trace_warning_symbol, |
253 | .stack = print_trace_stack, | 253 | .stack = print_trace_stack, |
254 | .address = print_trace_address, | 254 | .address = print_trace_address, |
255 | }; | 255 | }; |
256 | 256 | ||
257 | static void | 257 | static void |
@@ -351,15 +351,14 @@ void show_registers(struct pt_regs *regs) | |||
351 | printk(KERN_EMERG "Code: "); | 351 | printk(KERN_EMERG "Code: "); |
352 | 352 | ||
353 | ip = (u8 *)regs->ip - code_prologue; | 353 | ip = (u8 *)regs->ip - code_prologue; |
354 | if (ip < (u8 *)PAGE_OFFSET || | 354 | if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { |
355 | probe_kernel_address(ip, c)) { | ||
356 | /* try starting at EIP */ | 355 | /* try starting at EIP */ |
357 | ip = (u8 *)regs->ip; | 356 | ip = (u8 *)regs->ip; |
358 | code_len = code_len - code_prologue + 1; | 357 | code_len = code_len - code_prologue + 1; |
359 | } | 358 | } |
360 | for (i = 0; i < code_len; i++, ip++) { | 359 | for (i = 0; i < code_len; i++, ip++) { |
361 | if (ip < (u8 *)PAGE_OFFSET || | 360 | if (ip < (u8 *)PAGE_OFFSET || |
362 | probe_kernel_address(ip, c)) { | 361 | probe_kernel_address(ip, c)) { |
363 | printk(" Bad EIP value."); | 362 | printk(" Bad EIP value."); |
364 | break; | 363 | break; |
365 | } | 364 | } |
@@ -384,8 +383,6 @@ int is_valid_bugaddr(unsigned long ip) | |||
384 | return ud2 == 0x0b0f; | 383 | return ud2 == 0x0b0f; |
385 | } | 384 | } |
386 | 385 | ||
387 | static int die_counter; | ||
388 | |||
389 | int __kprobes __die(const char *str, struct pt_regs *regs, long err) | 386 | int __kprobes __die(const char *str, struct pt_regs *regs, long err) |
390 | { | 387 | { |
391 | unsigned short ss; | 388 | unsigned short ss; |
@@ -402,26 +399,22 @@ int __kprobes __die(const char *str, struct pt_regs *regs, long err) | |||
402 | printk("DEBUG_PAGEALLOC"); | 399 | printk("DEBUG_PAGEALLOC"); |
403 | #endif | 400 | #endif |
404 | printk("\n"); | 401 | printk("\n"); |
405 | |||
406 | if (notify_die(DIE_OOPS, str, regs, err, | 402 | if (notify_die(DIE_OOPS, str, regs, err, |
407 | current->thread.trap_no, SIGSEGV) != NOTIFY_STOP) { | 403 | current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) |
408 | 404 | return 1; | |
409 | show_registers(regs); | ||
410 | /* Executive summary in case the oops scrolled away */ | ||
411 | sp = (unsigned long) (®s->sp); | ||
412 | savesegment(ss, ss); | ||
413 | if (user_mode(regs)) { | ||
414 | sp = regs->sp; | ||
415 | ss = regs->ss & 0xffff; | ||
416 | } | ||
417 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); | ||
418 | print_symbol("%s", regs->ip); | ||
419 | printk(" SS:ESP %04x:%08lx\n", ss, sp); | ||
420 | 405 | ||
421 | return 0; | 406 | show_registers(regs); |
407 | /* Executive summary in case the oops scrolled away */ | ||
408 | sp = (unsigned long) (®s->sp); | ||
409 | savesegment(ss, ss); | ||
410 | if (user_mode(regs)) { | ||
411 | sp = regs->sp; | ||
412 | ss = regs->ss & 0xffff; | ||
422 | } | 413 | } |
423 | 414 | printk(KERN_EMERG "EIP: [<%08lx>] ", regs->ip); | |
424 | return 1; | 415 | print_symbol("%s", regs->ip); |
416 | printk(" SS:ESP %04x:%08lx\n", ss, sp); | ||
417 | return 0; | ||
425 | } | 418 | } |
426 | 419 | ||
427 | /* | 420 | /* |
@@ -546,7 +539,7 @@ void do_##name(struct pt_regs *regs, long error_code) \ | |||
546 | { \ | 539 | { \ |
547 | trace_hardirqs_fixup(); \ | 540 | trace_hardirqs_fixup(); \ |
548 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 541 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
549 | == NOTIFY_STOP) \ | 542 | == NOTIFY_STOP) \ |
550 | return; \ | 543 | return; \ |
551 | do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ | 544 | do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ |
552 | } | 545 | } |
@@ -562,7 +555,7 @@ void do_##name(struct pt_regs *regs, long error_code) \ | |||
562 | info.si_code = sicode; \ | 555 | info.si_code = sicode; \ |
563 | info.si_addr = (void __user *)siaddr; \ | 556 | info.si_addr = (void __user *)siaddr; \ |
564 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 557 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
565 | == NOTIFY_STOP) \ | 558 | == NOTIFY_STOP) \ |
566 | return; \ | 559 | return; \ |
567 | do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ | 560 | do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ |
568 | } | 561 | } |
@@ -571,7 +564,7 @@ void do_##name(struct pt_regs *regs, long error_code) \ | |||
571 | void do_##name(struct pt_regs *regs, long error_code) \ | 564 | void do_##name(struct pt_regs *regs, long error_code) \ |
572 | { \ | 565 | { \ |
573 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 566 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
574 | == NOTIFY_STOP) \ | 567 | == NOTIFY_STOP) \ |
575 | return; \ | 568 | return; \ |
576 | do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ | 569 | do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ |
577 | } | 570 | } |
@@ -586,27 +579,29 @@ void do_##name(struct pt_regs *regs, long error_code) \ | |||
586 | info.si_addr = (void __user *)siaddr; \ | 579 | info.si_addr = (void __user *)siaddr; \ |
587 | trace_hardirqs_fixup(); \ | 580 | trace_hardirqs_fixup(); \ |
588 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ | 581 | if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ |
589 | == NOTIFY_STOP) \ | 582 | == NOTIFY_STOP) \ |
590 | return; \ | 583 | return; \ |
591 | do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ | 584 | do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ |
592 | } | 585 | } |
593 | 586 | ||
594 | DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip) | 587 | DO_VM86_ERROR_INFO(0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->ip) |
595 | #ifndef CONFIG_KPROBES | 588 | #ifndef CONFIG_KPROBES |
596 | DO_VM86_ERROR(3, SIGTRAP, "int3", int3) | 589 | DO_VM86_ERROR(3, SIGTRAP, "int3", int3) |
597 | #endif | 590 | #endif |
598 | DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow) | 591 | DO_VM86_ERROR(4, SIGSEGV, "overflow", overflow) |
599 | DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds) | 592 | DO_VM86_ERROR(5, SIGSEGV, "bounds", bounds) |
600 | DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0) | 593 | DO_ERROR_INFO(6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->ip, 0) |
601 | DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) | 594 | DO_ERROR(9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) |
602 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) | 595 | DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) |
603 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) | 596 | DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) |
604 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) | 597 | DO_ERROR(12, SIGBUS, "stack segment", stack_segment) |
605 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0) | 598 | DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0, 0) |
606 | DO_ERROR_INFO(32, SIGILL, "iret exception", iret_error, ILL_BADSTK, 0, 1) | 599 | DO_ERROR_INFO(32, SIGILL, "iret exception", iret_error, ILL_BADSTK, 0, 1) |
607 | 600 | ||
608 | void __kprobes do_general_protection(struct pt_regs *regs, long error_code) | 601 | void __kprobes |
602 | do_general_protection(struct pt_regs *regs, long error_code) | ||
609 | { | 603 | { |
604 | struct task_struct *tsk; | ||
610 | struct thread_struct *thread; | 605 | struct thread_struct *thread; |
611 | struct tss_struct *tss; | 606 | struct tss_struct *tss; |
612 | int cpu; | 607 | int cpu; |
@@ -647,23 +642,24 @@ void __kprobes do_general_protection(struct pt_regs *regs, long error_code) | |||
647 | if (regs->flags & X86_VM_MASK) | 642 | if (regs->flags & X86_VM_MASK) |
648 | goto gp_in_vm86; | 643 | goto gp_in_vm86; |
649 | 644 | ||
645 | tsk = current; | ||
650 | if (!user_mode(regs)) | 646 | if (!user_mode(regs)) |
651 | goto gp_in_kernel; | 647 | goto gp_in_kernel; |
652 | 648 | ||
653 | current->thread.error_code = error_code; | 649 | tsk->thread.error_code = error_code; |
654 | current->thread.trap_no = 13; | 650 | tsk->thread.trap_no = 13; |
655 | 651 | ||
656 | if (show_unhandled_signals && unhandled_signal(current, SIGSEGV) && | 652 | if (show_unhandled_signals && unhandled_signal(tsk, SIGSEGV) && |
657 | printk_ratelimit()) { | 653 | printk_ratelimit()) { |
658 | printk(KERN_INFO | 654 | printk(KERN_INFO |
659 | "%s[%d] general protection ip:%lx sp:%lx error:%lx", | 655 | "%s[%d] general protection ip:%lx sp:%lx error:%lx", |
660 | current->comm, task_pid_nr(current), | 656 | tsk->comm, task_pid_nr(tsk), |
661 | regs->ip, regs->sp, error_code); | 657 | regs->ip, regs->sp, error_code); |
662 | print_vma_addr(" in ", regs->ip); | 658 | print_vma_addr(" in ", regs->ip); |
663 | printk("\n"); | 659 | printk("\n"); |
664 | } | 660 | } |
665 | 661 | ||
666 | force_sig(SIGSEGV, current); | 662 | force_sig(SIGSEGV, tsk); |
667 | return; | 663 | return; |
668 | 664 | ||
669 | gp_in_vm86: | 665 | gp_in_vm86: |
@@ -672,14 +668,15 @@ gp_in_vm86: | |||
672 | return; | 668 | return; |
673 | 669 | ||
674 | gp_in_kernel: | 670 | gp_in_kernel: |
675 | if (!fixup_exception(regs)) { | 671 | if (fixup_exception(regs)) |
676 | current->thread.error_code = error_code; | 672 | return; |
677 | current->thread.trap_no = 13; | 673 | |
678 | if (notify_die(DIE_GPF, "general protection fault", regs, | 674 | tsk->thread.error_code = error_code; |
675 | tsk->thread.trap_no = 13; | ||
676 | if (notify_die(DIE_GPF, "general protection fault", regs, | ||
679 | error_code, 13, SIGSEGV) == NOTIFY_STOP) | 677 | error_code, 13, SIGSEGV) == NOTIFY_STOP) |
680 | return; | 678 | return; |
681 | die("general protection fault", regs, error_code); | 679 | die("general protection fault", regs, error_code); |
682 | } | ||
683 | } | 680 | } |
684 | 681 | ||
685 | static notrace __kprobes void | 682 | static notrace __kprobes void |
@@ -756,9 +753,9 @@ unknown_nmi_error(unsigned char reason, struct pt_regs *regs) | |||
756 | 753 | ||
757 | static DEFINE_SPINLOCK(nmi_print_lock); | 754 | static DEFINE_SPINLOCK(nmi_print_lock); |
758 | 755 | ||
759 | void notrace __kprobes die_nmi(struct pt_regs *regs, const char *msg) | 756 | void notrace __kprobes die_nmi(char *str, struct pt_regs *regs, int do_panic) |
760 | { | 757 | { |
761 | if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == NOTIFY_STOP) | 758 | if (notify_die(DIE_NMIWATCHDOG, str, regs, 0, 2, SIGINT) == NOTIFY_STOP) |
762 | return; | 759 | return; |
763 | 760 | ||
764 | spin_lock(&nmi_print_lock); | 761 | spin_lock(&nmi_print_lock); |
@@ -767,10 +764,12 @@ void notrace __kprobes die_nmi(struct pt_regs *regs, const char *msg) | |||
767 | * to get a message out: | 764 | * to get a message out: |
768 | */ | 765 | */ |
769 | bust_spinlocks(1); | 766 | bust_spinlocks(1); |
770 | printk(KERN_EMERG "%s", msg); | 767 | printk(KERN_EMERG "%s", str); |
771 | printk(" on CPU%d, ip %08lx, registers:\n", | 768 | printk(" on CPU%d, ip %08lx, registers:\n", |
772 | smp_processor_id(), regs->ip); | 769 | smp_processor_id(), regs->ip); |
773 | show_registers(regs); | 770 | show_registers(regs); |
771 | if (do_panic) | ||
772 | panic("Non maskable interrupt"); | ||
774 | console_silent(); | 773 | console_silent(); |
775 | spin_unlock(&nmi_print_lock); | 774 | spin_unlock(&nmi_print_lock); |
776 | bust_spinlocks(0); | 775 | bust_spinlocks(0); |
@@ -790,14 +789,17 @@ void notrace __kprobes die_nmi(struct pt_regs *regs, const char *msg) | |||
790 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | 789 | static notrace __kprobes void default_do_nmi(struct pt_regs *regs) |
791 | { | 790 | { |
792 | unsigned char reason = 0; | 791 | unsigned char reason = 0; |
792 | int cpu; | ||
793 | |||
794 | cpu = smp_processor_id(); | ||
793 | 795 | ||
794 | /* Only the BSP gets external NMIs from the system: */ | 796 | /* Only the BSP gets external NMIs from the system. */ |
795 | if (!smp_processor_id()) | 797 | if (!cpu) |
796 | reason = get_nmi_reason(); | 798 | reason = get_nmi_reason(); |
797 | 799 | ||
798 | if (!(reason & 0xc0)) { | 800 | if (!(reason & 0xc0)) { |
799 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) | 801 | if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) |
800 | == NOTIFY_STOP) | 802 | == NOTIFY_STOP) |
801 | return; | 803 | return; |
802 | #ifdef CONFIG_X86_LOCAL_APIC | 804 | #ifdef CONFIG_X86_LOCAL_APIC |
803 | /* | 805 | /* |
@@ -806,7 +808,7 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | |||
806 | */ | 808 | */ |
807 | if (nmi_watchdog_tick(regs, reason)) | 809 | if (nmi_watchdog_tick(regs, reason)) |
808 | return; | 810 | return; |
809 | if (!do_nmi_callback(regs, smp_processor_id())) | 811 | if (!do_nmi_callback(regs, cpu)) |
810 | unknown_nmi_error(reason, regs); | 812 | unknown_nmi_error(reason, regs); |
811 | #else | 813 | #else |
812 | unknown_nmi_error(reason, regs); | 814 | unknown_nmi_error(reason, regs); |
@@ -816,6 +818,8 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | |||
816 | } | 818 | } |
817 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) | 819 | if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) |
818 | return; | 820 | return; |
821 | |||
822 | /* AK: following checks seem to be broken on modern chipsets. FIXME */ | ||
819 | if (reason & 0x80) | 823 | if (reason & 0x80) |
820 | mem_parity_error(reason, regs); | 824 | mem_parity_error(reason, regs); |
821 | if (reason & 0x40) | 825 | if (reason & 0x40) |
@@ -827,8 +831,6 @@ static notrace __kprobes void default_do_nmi(struct pt_regs *regs) | |||
827 | reassert_nmi(); | 831 | reassert_nmi(); |
828 | } | 832 | } |
829 | 833 | ||
830 | static int ignore_nmis; | ||
831 | |||
832 | notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code) | 834 | notrace __kprobes void do_nmi(struct pt_regs *regs, long error_code) |
833 | { | 835 | { |
834 | int cpu; | 836 | int cpu; |
@@ -913,7 +915,7 @@ void __kprobes do_debug(struct pt_regs *regs, long error_code) | |||
913 | tsk->thread.debugctlmsr = 0; | 915 | tsk->thread.debugctlmsr = 0; |
914 | 916 | ||
915 | if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, | 917 | if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, |
916 | SIGTRAP) == NOTIFY_STOP) | 918 | SIGTRAP) == NOTIFY_STOP) |
917 | return; | 919 | return; |
918 | /* It's safe to allow irq's after DR6 has been saved */ | 920 | /* It's safe to allow irq's after DR6 has been saved */ |
919 | if (regs->flags & X86_EFLAGS_IF) | 921 | if (regs->flags & X86_EFLAGS_IF) |
@@ -974,9 +976,8 @@ clear_TF_reenable: | |||
974 | void math_error(void __user *ip) | 976 | void math_error(void __user *ip) |
975 | { | 977 | { |
976 | struct task_struct *task; | 978 | struct task_struct *task; |
977 | unsigned short cwd; | ||
978 | unsigned short swd; | ||
979 | siginfo_t info; | 979 | siginfo_t info; |
980 | unsigned short cwd, swd; | ||
980 | 981 | ||
981 | /* | 982 | /* |
982 | * Save the info for the exception handler and clear the error. | 983 | * Save the info for the exception handler and clear the error. |
@@ -995,7 +996,7 @@ void math_error(void __user *ip) | |||
995 | * C1 reg you need in case of a stack fault, 0x040 is the stack | 996 | * C1 reg you need in case of a stack fault, 0x040 is the stack |
996 | * fault bit. We should only be taking one exception at a time, | 997 | * fault bit. We should only be taking one exception at a time, |
997 | * so if this combination doesn't produce any single exception, | 998 | * so if this combination doesn't produce any single exception, |
998 | * then we have a bad program that isn't syncronizing its FPU usage | 999 | * then we have a bad program that isn't synchronizing its FPU usage |
999 | * and it will suffer the consequences since we won't be able to | 1000 | * and it will suffer the consequences since we won't be able to |
1000 | * fully reproduce the context of the exception | 1001 | * fully reproduce the context of the exception |
1001 | */ | 1002 | */ |
@@ -1004,7 +1005,7 @@ void math_error(void __user *ip) | |||
1004 | switch (swd & ~cwd & 0x3f) { | 1005 | switch (swd & ~cwd & 0x3f) { |
1005 | case 0x000: /* No unmasked exception */ | 1006 | case 0x000: /* No unmasked exception */ |
1006 | return; | 1007 | return; |
1007 | default: /* Multiple exceptions */ | 1008 | default: /* Multiple exceptions */ |
1008 | break; | 1009 | break; |
1009 | case 0x001: /* Invalid Op */ | 1010 | case 0x001: /* Invalid Op */ |
1010 | /* | 1011 | /* |
@@ -1040,8 +1041,8 @@ void do_coprocessor_error(struct pt_regs *regs, long error_code) | |||
1040 | static void simd_math_error(void __user *ip) | 1041 | static void simd_math_error(void __user *ip) |
1041 | { | 1042 | { |
1042 | struct task_struct *task; | 1043 | struct task_struct *task; |
1043 | unsigned short mxcsr; | ||
1044 | siginfo_t info; | 1044 | siginfo_t info; |
1045 | unsigned short mxcsr; | ||
1045 | 1046 | ||
1046 | /* | 1047 | /* |
1047 | * Save the info for the exception handler and clear the error. | 1048 | * Save the info for the exception handler and clear the error. |
@@ -1117,7 +1118,7 @@ void do_spurious_interrupt_bug(struct pt_regs *regs, long error_code) | |||
1117 | 1118 | ||
1118 | unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) | 1119 | unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) |
1119 | { | 1120 | { |
1120 | struct desc_struct *gdt = __get_cpu_var(gdt_page).gdt; | 1121 | struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id()); |
1121 | unsigned long base = (kesp - uesp) & -THREAD_SIZE; | 1122 | unsigned long base = (kesp - uesp) & -THREAD_SIZE; |
1122 | unsigned long new_kesp = kesp - base; | 1123 | unsigned long new_kesp = kesp - base; |
1123 | unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; | 1124 | unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; |
@@ -1196,19 +1197,16 @@ void __init trap_init(void) | |||
1196 | early_iounmap(p, 4); | 1197 | early_iounmap(p, 4); |
1197 | #endif | 1198 | #endif |
1198 | 1199 | ||
1199 | #ifdef CONFIG_X86_LOCAL_APIC | 1200 | set_trap_gate(0, ÷_error); |
1200 | init_apic_mappings(); | 1201 | set_intr_gate(1, &debug); |
1201 | #endif | 1202 | set_intr_gate(2, &nmi); |
1202 | set_trap_gate(0, ÷_error); | 1203 | set_system_intr_gate(3, &int3); /* int3 can be called from all */ |
1203 | set_intr_gate(1, &debug); | 1204 | set_system_gate(4, &overflow); /* int4 can be called from all */ |
1204 | set_intr_gate(2, &nmi); | 1205 | set_trap_gate(5, &bounds); |
1205 | set_system_intr_gate(3, &int3); /* int3/4 can be called from all */ | 1206 | set_trap_gate(6, &invalid_op); |
1206 | set_system_gate(4, &overflow); | 1207 | set_trap_gate(7, &device_not_available); |
1207 | set_trap_gate(5, &bounds); | 1208 | set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS); |
1208 | set_trap_gate(6, &invalid_op); | 1209 | set_trap_gate(9, &coprocessor_segment_overrun); |
1209 | set_trap_gate(7, &device_not_available); | ||
1210 | set_task_gate(8, GDT_ENTRY_DOUBLEFAULT_TSS); | ||
1211 | set_trap_gate(9, &coprocessor_segment_overrun); | ||
1212 | set_trap_gate(10, &invalid_TSS); | 1210 | set_trap_gate(10, &invalid_TSS); |
1213 | set_trap_gate(11, &segment_not_present); | 1211 | set_trap_gate(11, &segment_not_present); |
1214 | set_trap_gate(12, &stack_segment); | 1212 | set_trap_gate(12, &stack_segment); |