diff options
Diffstat (limited to 'arch/powerpc/kernel/traps.c')
-rw-r--r-- | arch/powerpc/kernel/traps.c | 178 |
1 files changed, 113 insertions, 65 deletions
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c index 6f0ae1a9bfae..29d128eb6c43 100644 --- a/arch/powerpc/kernel/traps.c +++ b/arch/powerpc/kernel/traps.c | |||
@@ -21,7 +21,6 @@ | |||
21 | #include <linux/stddef.h> | 21 | #include <linux/stddef.h> |
22 | #include <linux/unistd.h> | 22 | #include <linux/unistd.h> |
23 | #include <linux/ptrace.h> | 23 | #include <linux/ptrace.h> |
24 | #include <linux/slab.h> | ||
25 | #include <linux/user.h> | 24 | #include <linux/user.h> |
26 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
27 | #include <linux/init.h> | 26 | #include <linux/init.h> |
@@ -60,13 +59,13 @@ | |||
60 | #endif | 59 | #endif |
61 | 60 | ||
62 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) | 61 | #if defined(CONFIG_DEBUGGER) || defined(CONFIG_KEXEC) |
63 | int (*__debugger)(struct pt_regs *regs); | 62 | int (*__debugger)(struct pt_regs *regs) __read_mostly; |
64 | int (*__debugger_ipi)(struct pt_regs *regs); | 63 | int (*__debugger_ipi)(struct pt_regs *regs) __read_mostly; |
65 | int (*__debugger_bpt)(struct pt_regs *regs); | 64 | int (*__debugger_bpt)(struct pt_regs *regs) __read_mostly; |
66 | int (*__debugger_sstep)(struct pt_regs *regs); | 65 | int (*__debugger_sstep)(struct pt_regs *regs) __read_mostly; |
67 | int (*__debugger_iabr_match)(struct pt_regs *regs); | 66 | int (*__debugger_iabr_match)(struct pt_regs *regs) __read_mostly; |
68 | int (*__debugger_dabr_match)(struct pt_regs *regs); | 67 | int (*__debugger_dabr_match)(struct pt_regs *regs) __read_mostly; |
69 | int (*__debugger_fault_handler)(struct pt_regs *regs); | 68 | int (*__debugger_fault_handler)(struct pt_regs *regs) __read_mostly; |
70 | 69 | ||
71 | EXPORT_SYMBOL(__debugger); | 70 | EXPORT_SYMBOL(__debugger); |
72 | EXPORT_SYMBOL(__debugger_ipi); | 71 | EXPORT_SYMBOL(__debugger_ipi); |
@@ -102,11 +101,11 @@ static inline void pmac_backlight_unblank(void) { } | |||
102 | int die(const char *str, struct pt_regs *regs, long err) | 101 | int die(const char *str, struct pt_regs *regs, long err) |
103 | { | 102 | { |
104 | static struct { | 103 | static struct { |
105 | spinlock_t lock; | 104 | raw_spinlock_t lock; |
106 | u32 lock_owner; | 105 | u32 lock_owner; |
107 | int lock_owner_depth; | 106 | int lock_owner_depth; |
108 | } die = { | 107 | } die = { |
109 | .lock = __SPIN_LOCK_UNLOCKED(die.lock), | 108 | .lock = __RAW_SPIN_LOCK_UNLOCKED(die.lock), |
110 | .lock_owner = -1, | 109 | .lock_owner = -1, |
111 | .lock_owner_depth = 0 | 110 | .lock_owner_depth = 0 |
112 | }; | 111 | }; |
@@ -120,7 +119,7 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
120 | 119 | ||
121 | if (die.lock_owner != raw_smp_processor_id()) { | 120 | if (die.lock_owner != raw_smp_processor_id()) { |
122 | console_verbose(); | 121 | console_verbose(); |
123 | spin_lock_irqsave(&die.lock, flags); | 122 | raw_spin_lock_irqsave(&die.lock, flags); |
124 | die.lock_owner = smp_processor_id(); | 123 | die.lock_owner = smp_processor_id(); |
125 | die.lock_owner_depth = 0; | 124 | die.lock_owner_depth = 0; |
126 | bust_spinlocks(1); | 125 | bust_spinlocks(1); |
@@ -146,6 +145,11 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
146 | #endif | 145 | #endif |
147 | printk("%s\n", ppc_md.name ? ppc_md.name : ""); | 146 | printk("%s\n", ppc_md.name ? ppc_md.name : ""); |
148 | 147 | ||
148 | sysfs_printk_last_file(); | ||
149 | if (notify_die(DIE_OOPS, str, regs, err, 255, | ||
150 | SIGSEGV) == NOTIFY_STOP) | ||
151 | return 1; | ||
152 | |||
149 | print_modules(); | 153 | print_modules(); |
150 | show_regs(regs); | 154 | show_regs(regs); |
151 | } else { | 155 | } else { |
@@ -155,7 +159,7 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
155 | bust_spinlocks(0); | 159 | bust_spinlocks(0); |
156 | die.lock_owner = -1; | 160 | die.lock_owner = -1; |
157 | add_taint(TAINT_DIE); | 161 | add_taint(TAINT_DIE); |
158 | spin_unlock_irqrestore(&die.lock, flags); | 162 | raw_spin_unlock_irqrestore(&die.lock, flags); |
159 | 163 | ||
160 | if (kexec_should_crash(current) || | 164 | if (kexec_should_crash(current) || |
161 | kexec_sr_activated(smp_processor_id())) | 165 | kexec_sr_activated(smp_processor_id())) |
@@ -174,6 +178,15 @@ int die(const char *str, struct pt_regs *regs, long err) | |||
174 | return 0; | 178 | return 0; |
175 | } | 179 | } |
176 | 180 | ||
181 | void user_single_step_siginfo(struct task_struct *tsk, | ||
182 | struct pt_regs *regs, siginfo_t *info) | ||
183 | { | ||
184 | memset(info, 0, sizeof(*info)); | ||
185 | info->si_signo = SIGTRAP; | ||
186 | info->si_code = TRAP_TRACE; | ||
187 | info->si_addr = (void __user *)regs->nip; | ||
188 | } | ||
189 | |||
177 | void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | 190 | void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) |
178 | { | 191 | { |
179 | siginfo_t info; | 192 | siginfo_t info; |
@@ -198,28 +211,6 @@ void _exception(int signr, struct pt_regs *regs, int code, unsigned long addr) | |||
198 | info.si_code = code; | 211 | info.si_code = code; |
199 | info.si_addr = (void __user *) addr; | 212 | info.si_addr = (void __user *) addr; |
200 | force_sig_info(signr, &info, current); | 213 | force_sig_info(signr, &info, current); |
201 | |||
202 | /* | ||
203 | * Init gets no signals that it doesn't have a handler for. | ||
204 | * That's all very well, but if it has caused a synchronous | ||
205 | * exception and we ignore the resulting signal, it will just | ||
206 | * generate the same exception over and over again and we get | ||
207 | * nowhere. Better to kill it and let the kernel panic. | ||
208 | */ | ||
209 | if (is_global_init(current)) { | ||
210 | __sighandler_t handler; | ||
211 | |||
212 | spin_lock_irq(¤t->sighand->siglock); | ||
213 | handler = current->sighand->action[signr-1].sa.sa_handler; | ||
214 | spin_unlock_irq(¤t->sighand->siglock); | ||
215 | if (handler == SIG_DFL) { | ||
216 | /* init has generated a synchronous exception | ||
217 | and it doesn't have a handler for the signal */ | ||
218 | printk(KERN_CRIT "init has generated signal %d " | ||
219 | "but has no handler for it\n", signr); | ||
220 | do_exit(signr); | ||
221 | } | ||
222 | } | ||
223 | } | 214 | } |
224 | 215 | ||
225 | #ifdef CONFIG_PPC64 | 216 | #ifdef CONFIG_PPC64 |
@@ -307,7 +298,7 @@ static inline int check_io_access(struct pt_regs *regs) | |||
307 | return 0; | 298 | return 0; |
308 | } | 299 | } |
309 | 300 | ||
310 | #if defined(CONFIG_4xx) || defined(CONFIG_BOOKE) | 301 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
311 | /* On 4xx, the reason for the machine check or program exception | 302 | /* On 4xx, the reason for the machine check or program exception |
312 | is in the ESR. */ | 303 | is in the ESR. */ |
313 | #define get_reason(regs) ((regs)->dsisr) | 304 | #define get_reason(regs) ((regs)->dsisr) |
@@ -491,6 +482,8 @@ void machine_check_exception(struct pt_regs *regs) | |||
491 | { | 482 | { |
492 | int recover = 0; | 483 | int recover = 0; |
493 | 484 | ||
485 | __get_cpu_var(irq_stat).mce_exceptions++; | ||
486 | |||
494 | /* See if any machine dependent calls. In theory, we would want | 487 | /* See if any machine dependent calls. In theory, we would want |
495 | * to call the CPU first, and call the ppc_md. one if the CPU | 488 | * to call the CPU first, and call the ppc_md. one if the CPU |
496 | * one returns a positive number. However there is existing code | 489 | * one returns a positive number. However there is existing code |
@@ -759,7 +752,7 @@ static int emulate_instruction(struct pt_regs *regs) | |||
759 | 752 | ||
760 | /* Emulate the mfspr rD, PVR. */ | 753 | /* Emulate the mfspr rD, PVR. */ |
761 | if ((instword & PPC_INST_MFSPR_PVR_MASK) == PPC_INST_MFSPR_PVR) { | 754 | if ((instword & PPC_INST_MFSPR_PVR_MASK) == PPC_INST_MFSPR_PVR) { |
762 | PPC_WARN_EMULATED(mfpvr); | 755 | PPC_WARN_EMULATED(mfpvr, regs); |
763 | rd = (instword >> 21) & 0x1f; | 756 | rd = (instword >> 21) & 0x1f; |
764 | regs->gpr[rd] = mfspr(SPRN_PVR); | 757 | regs->gpr[rd] = mfspr(SPRN_PVR); |
765 | return 0; | 758 | return 0; |
@@ -767,7 +760,7 @@ static int emulate_instruction(struct pt_regs *regs) | |||
767 | 760 | ||
768 | /* Emulating the dcba insn is just a no-op. */ | 761 | /* Emulating the dcba insn is just a no-op. */ |
769 | if ((instword & PPC_INST_DCBA_MASK) == PPC_INST_DCBA) { | 762 | if ((instword & PPC_INST_DCBA_MASK) == PPC_INST_DCBA) { |
770 | PPC_WARN_EMULATED(dcba); | 763 | PPC_WARN_EMULATED(dcba, regs); |
771 | return 0; | 764 | return 0; |
772 | } | 765 | } |
773 | 766 | ||
@@ -776,7 +769,7 @@ static int emulate_instruction(struct pt_regs *regs) | |||
776 | int shift = (instword >> 21) & 0x1c; | 769 | int shift = (instword >> 21) & 0x1c; |
777 | unsigned long msk = 0xf0000000UL >> shift; | 770 | unsigned long msk = 0xf0000000UL >> shift; |
778 | 771 | ||
779 | PPC_WARN_EMULATED(mcrxr); | 772 | PPC_WARN_EMULATED(mcrxr, regs); |
780 | regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); | 773 | regs->ccr = (regs->ccr & ~msk) | ((regs->xer >> shift) & msk); |
781 | regs->xer &= ~0xf0000000UL; | 774 | regs->xer &= ~0xf0000000UL; |
782 | return 0; | 775 | return 0; |
@@ -784,19 +777,19 @@ static int emulate_instruction(struct pt_regs *regs) | |||
784 | 777 | ||
785 | /* Emulate load/store string insn. */ | 778 | /* Emulate load/store string insn. */ |
786 | if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) { | 779 | if ((instword & PPC_INST_STRING_GEN_MASK) == PPC_INST_STRING) { |
787 | PPC_WARN_EMULATED(string); | 780 | PPC_WARN_EMULATED(string, regs); |
788 | return emulate_string_inst(regs, instword); | 781 | return emulate_string_inst(regs, instword); |
789 | } | 782 | } |
790 | 783 | ||
791 | /* Emulate the popcntb (Population Count Bytes) instruction. */ | 784 | /* Emulate the popcntb (Population Count Bytes) instruction. */ |
792 | if ((instword & PPC_INST_POPCNTB_MASK) == PPC_INST_POPCNTB) { | 785 | if ((instword & PPC_INST_POPCNTB_MASK) == PPC_INST_POPCNTB) { |
793 | PPC_WARN_EMULATED(popcntb); | 786 | PPC_WARN_EMULATED(popcntb, regs); |
794 | return emulate_popcntb_inst(regs, instword); | 787 | return emulate_popcntb_inst(regs, instword); |
795 | } | 788 | } |
796 | 789 | ||
797 | /* Emulate isel (Integer Select) instruction */ | 790 | /* Emulate isel (Integer Select) instruction */ |
798 | if ((instword & PPC_INST_ISEL_MASK) == PPC_INST_ISEL) { | 791 | if ((instword & PPC_INST_ISEL_MASK) == PPC_INST_ISEL) { |
799 | PPC_WARN_EMULATED(isel); | 792 | PPC_WARN_EMULATED(isel, regs); |
800 | return emulate_isel(regs, instword); | 793 | return emulate_isel(regs, instword); |
801 | } | 794 | } |
802 | 795 | ||
@@ -973,6 +966,8 @@ void vsx_unavailable_exception(struct pt_regs *regs) | |||
973 | 966 | ||
974 | void performance_monitor_exception(struct pt_regs *regs) | 967 | void performance_monitor_exception(struct pt_regs *regs) |
975 | { | 968 | { |
969 | __get_cpu_var(irq_stat).pmu_irqs++; | ||
970 | |||
976 | perf_irq(regs); | 971 | perf_irq(regs); |
977 | } | 972 | } |
978 | 973 | ||
@@ -995,7 +990,7 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
995 | #ifdef CONFIG_MATH_EMULATION | 990 | #ifdef CONFIG_MATH_EMULATION |
996 | errcode = do_mathemu(regs); | 991 | errcode = do_mathemu(regs); |
997 | if (errcode >= 0) | 992 | if (errcode >= 0) |
998 | PPC_WARN_EMULATED(math); | 993 | PPC_WARN_EMULATED(math, regs); |
999 | 994 | ||
1000 | switch (errcode) { | 995 | switch (errcode) { |
1001 | case 0: | 996 | case 0: |
@@ -1018,7 +1013,7 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
1018 | #elif defined(CONFIG_8XX_MINIMAL_FPEMU) | 1013 | #elif defined(CONFIG_8XX_MINIMAL_FPEMU) |
1019 | errcode = Soft_emulate_8xx(regs); | 1014 | errcode = Soft_emulate_8xx(regs); |
1020 | if (errcode >= 0) | 1015 | if (errcode >= 0) |
1021 | PPC_WARN_EMULATED(8xx); | 1016 | PPC_WARN_EMULATED(8xx, regs); |
1022 | 1017 | ||
1023 | switch (errcode) { | 1018 | switch (errcode) { |
1024 | case 0: | 1019 | case 0: |
@@ -1037,10 +1032,69 @@ void SoftwareEmulation(struct pt_regs *regs) | |||
1037 | } | 1032 | } |
1038 | #endif /* CONFIG_8xx */ | 1033 | #endif /* CONFIG_8xx */ |
1039 | 1034 | ||
1040 | #if defined(CONFIG_40x) || defined(CONFIG_BOOKE) | 1035 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
1036 | static void handle_debug(struct pt_regs *regs, unsigned long debug_status) | ||
1037 | { | ||
1038 | int changed = 0; | ||
1039 | /* | ||
1040 | * Determine the cause of the debug event, clear the | ||
1041 | * event flags and send a trap to the handler. Torez | ||
1042 | */ | ||
1043 | if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) { | ||
1044 | dbcr_dac(current) &= ~(DBCR_DAC1R | DBCR_DAC1W); | ||
1045 | #ifdef CONFIG_PPC_ADV_DEBUG_DAC_RANGE | ||
1046 | current->thread.dbcr2 &= ~DBCR2_DAC12MODE; | ||
1047 | #endif | ||
1048 | do_send_trap(regs, mfspr(SPRN_DAC1), debug_status, TRAP_HWBKPT, | ||
1049 | 5); | ||
1050 | changed |= 0x01; | ||
1051 | } else if (debug_status & (DBSR_DAC2R | DBSR_DAC2W)) { | ||
1052 | dbcr_dac(current) &= ~(DBCR_DAC2R | DBCR_DAC2W); | ||
1053 | do_send_trap(regs, mfspr(SPRN_DAC2), debug_status, TRAP_HWBKPT, | ||
1054 | 6); | ||
1055 | changed |= 0x01; | ||
1056 | } else if (debug_status & DBSR_IAC1) { | ||
1057 | current->thread.dbcr0 &= ~DBCR0_IAC1; | ||
1058 | dbcr_iac_range(current) &= ~DBCR_IAC12MODE; | ||
1059 | do_send_trap(regs, mfspr(SPRN_IAC1), debug_status, TRAP_HWBKPT, | ||
1060 | 1); | ||
1061 | changed |= 0x01; | ||
1062 | } else if (debug_status & DBSR_IAC2) { | ||
1063 | current->thread.dbcr0 &= ~DBCR0_IAC2; | ||
1064 | do_send_trap(regs, mfspr(SPRN_IAC2), debug_status, TRAP_HWBKPT, | ||
1065 | 2); | ||
1066 | changed |= 0x01; | ||
1067 | } else if (debug_status & DBSR_IAC3) { | ||
1068 | current->thread.dbcr0 &= ~DBCR0_IAC3; | ||
1069 | dbcr_iac_range(current) &= ~DBCR_IAC34MODE; | ||
1070 | do_send_trap(regs, mfspr(SPRN_IAC3), debug_status, TRAP_HWBKPT, | ||
1071 | 3); | ||
1072 | changed |= 0x01; | ||
1073 | } else if (debug_status & DBSR_IAC4) { | ||
1074 | current->thread.dbcr0 &= ~DBCR0_IAC4; | ||
1075 | do_send_trap(regs, mfspr(SPRN_IAC4), debug_status, TRAP_HWBKPT, | ||
1076 | 4); | ||
1077 | changed |= 0x01; | ||
1078 | } | ||
1079 | /* | ||
1080 | * At the point this routine was called, the MSR(DE) was turned off. | ||
1081 | * Check all other debug flags and see if that bit needs to be turned | ||
1082 | * back on or not. | ||
1083 | */ | ||
1084 | if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, current->thread.dbcr1)) | ||
1085 | regs->msr |= MSR_DE; | ||
1086 | else | ||
1087 | /* Make sure the IDM flag is off */ | ||
1088 | current->thread.dbcr0 &= ~DBCR0_IDM; | ||
1089 | |||
1090 | if (changed & 0x01) | ||
1091 | mtspr(SPRN_DBCR0, current->thread.dbcr0); | ||
1092 | } | ||
1041 | 1093 | ||
1042 | void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) | 1094 | void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) |
1043 | { | 1095 | { |
1096 | current->thread.dbsr = debug_status; | ||
1097 | |||
1044 | /* Hack alert: On BookE, Branch Taken stops on the branch itself, while | 1098 | /* Hack alert: On BookE, Branch Taken stops on the branch itself, while |
1045 | * on server, it stops on the target of the branch. In order to simulate | 1099 | * on server, it stops on the target of the branch. In order to simulate |
1046 | * the server behaviour, we thus restart right away with a single step | 1100 | * the server behaviour, we thus restart right away with a single step |
@@ -1084,29 +1138,23 @@ void __kprobes DebugException(struct pt_regs *regs, unsigned long debug_status) | |||
1084 | if (debugger_sstep(regs)) | 1138 | if (debugger_sstep(regs)) |
1085 | return; | 1139 | return; |
1086 | 1140 | ||
1087 | if (user_mode(regs)) | ||
1088 | current->thread.dbcr0 &= ~(DBCR0_IC); | ||
1089 | |||
1090 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); | ||
1091 | } else if (debug_status & (DBSR_DAC1R | DBSR_DAC1W)) { | ||
1092 | regs->msr &= ~MSR_DE; | ||
1093 | |||
1094 | if (user_mode(regs)) { | 1141 | if (user_mode(regs)) { |
1095 | current->thread.dbcr0 &= ~(DBSR_DAC1R | DBSR_DAC1W | | 1142 | current->thread.dbcr0 &= ~DBCR0_IC; |
1096 | DBCR0_IDM); | 1143 | #ifdef CONFIG_PPC_ADV_DEBUG_REGS |
1097 | } else { | 1144 | if (DBCR_ACTIVE_EVENTS(current->thread.dbcr0, |
1098 | /* Disable DAC interupts */ | 1145 | current->thread.dbcr1)) |
1099 | mtspr(SPRN_DBCR0, mfspr(SPRN_DBCR0) & ~(DBSR_DAC1R | | 1146 | regs->msr |= MSR_DE; |
1100 | DBSR_DAC1W | DBCR0_IDM)); | 1147 | else |
1101 | 1148 | /* Make sure the IDM bit is off */ | |
1102 | /* Clear the DAC event */ | 1149 | current->thread.dbcr0 &= ~DBCR0_IDM; |
1103 | mtspr(SPRN_DBSR, (DBSR_DAC1R | DBSR_DAC1W)); | 1150 | #endif |
1104 | } | 1151 | } |
1105 | /* Setup and send the trap to the handler */ | 1152 | |
1106 | do_dabr(regs, mfspr(SPRN_DAC1), debug_status); | 1153 | _exception(SIGTRAP, regs, TRAP_TRACE, regs->nip); |
1107 | } | 1154 | } else |
1155 | handle_debug(regs, debug_status); | ||
1108 | } | 1156 | } |
1109 | #endif /* CONFIG_4xx || CONFIG_BOOKE */ | 1157 | #endif /* CONFIG_PPC_ADV_DEBUG_REGS */ |
1110 | 1158 | ||
1111 | #if !defined(CONFIG_TAU_INT) | 1159 | #if !defined(CONFIG_TAU_INT) |
1112 | void TAUException(struct pt_regs *regs) | 1160 | void TAUException(struct pt_regs *regs) |
@@ -1129,7 +1177,7 @@ void altivec_assist_exception(struct pt_regs *regs) | |||
1129 | 1177 | ||
1130 | flush_altivec_to_thread(current); | 1178 | flush_altivec_to_thread(current); |
1131 | 1179 | ||
1132 | PPC_WARN_EMULATED(altivec); | 1180 | PPC_WARN_EMULATED(altivec, regs); |
1133 | err = emulate_altivec(regs); | 1181 | err = emulate_altivec(regs); |
1134 | if (err == 0) { | 1182 | if (err == 0) { |
1135 | regs->nip += 4; /* skip emulated instruction */ | 1183 | regs->nip += 4; /* skip emulated instruction */ |