|
15 | 15 | #include <linux/rtc.h>
|
16 | 16 | #include <linux/uaccess.h>
|
17 | 17 | #include <linux/kprobes.h>
|
| 18 | +#include <linux/kdebug.h> |
| 19 | +#include <linux/sched/debug.h> |
18 | 20 |
|
19 | 21 | #include <asm/setup.h>
|
20 | 22 | #include <asm/traps.h>
|
|
27 | 29 | #include <abi/fpu.h>
|
28 | 30 | #endif
|
29 | 31 |
|
| 32 | +int show_unhandled_signals = 1; |
| 33 | + |
30 | 34 | /* Defined in entry.S */
|
31 | 35 | asmlinkage void csky_trap(void);
|
32 | 36 |
|
@@ -77,117 +81,184 @@ void __init trap_init(void)
|
77 | 81 | #endif
|
78 | 82 | }
|
79 | 83 |
|
80 |
| -void die_if_kernel(char *str, struct pt_regs *regs, int nr) |
| 84 | +static DEFINE_SPINLOCK(die_lock); |
| 85 | + |
| 86 | +void die(struct pt_regs *regs, const char *str) |
81 | 87 | {
|
82 |
| - if (user_mode(regs)) |
83 |
| - return; |
| 88 | + static int die_counter; |
| 89 | + int ret; |
84 | 90 |
|
| 91 | + oops_enter(); |
| 92 | + |
| 93 | + spin_lock_irq(&die_lock); |
85 | 94 | console_verbose();
|
86 |
| - pr_err("%s: %08x\n", str, nr); |
| 95 | + bust_spinlocks(1); |
| 96 | + |
| 97 | + pr_emerg("%s [#%d]\n", str, ++die_counter); |
| 98 | + print_modules(); |
87 | 99 | show_regs(regs);
|
| 100 | + show_stack(current, (unsigned long *)regs->regs[4], KERN_INFO); |
| 101 | + |
| 102 | + ret = notify_die(DIE_OOPS, str, regs, 0, trap_no(regs), SIGSEGV); |
| 103 | + |
| 104 | + bust_spinlocks(0); |
88 | 105 | add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
|
89 |
| - do_exit(SIGSEGV); |
| 106 | + spin_unlock_irq(&die_lock); |
| 107 | + oops_exit(); |
| 108 | + |
| 109 | + if (in_interrupt()) |
| 110 | + panic("Fatal exception in interrupt"); |
| 111 | + if (panic_on_oops) |
| 112 | + panic("Fatal exception"); |
| 113 | + if (ret != NOTIFY_STOP) |
| 114 | + do_exit(SIGSEGV); |
90 | 115 | }
|
91 | 116 |
|
92 |
| -void buserr(struct pt_regs *regs) |
| 117 | +void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr) |
93 | 118 | {
|
94 |
| -#ifdef CONFIG_CPU_CK810 |
95 |
| - static unsigned long prev_pc; |
| 119 | + struct task_struct *tsk = current; |
96 | 120 |
|
97 |
| - if ((regs->pc == prev_pc) && prev_pc != 0) { |
98 |
| - prev_pc = 0; |
99 |
| - } else { |
100 |
| - prev_pc = regs->pc; |
101 |
| - return; |
| 121 | + if (show_unhandled_signals && unhandled_signal(tsk, signo) |
| 122 | + && printk_ratelimit()) { |
| 123 | + pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x%08lx", |
| 124 | + tsk->comm, task_pid_nr(tsk), signo, code, addr); |
| 125 | + print_vma_addr(KERN_CONT " in ", instruction_pointer(regs)); |
| 126 | + pr_cont("\n"); |
| 127 | + show_regs(regs); |
102 | 128 | }
|
103 |
| -#endif |
104 | 129 |
|
105 |
| - die_if_kernel("Kernel mode BUS error", regs, 0); |
| 130 | + force_sig_fault(signo, code, (void __user *)addr); |
| 131 | +} |
106 | 132 |
|
107 |
| - pr_err("User mode Bus Error\n"); |
108 |
| - show_regs(regs); |
| 133 | +static void do_trap_error(struct pt_regs *regs, int signo, int code, |
| 134 | + unsigned long addr, const char *str) |
| 135 | +{ |
| 136 | + current->thread.trap_no = trap_no(regs); |
109 | 137 |
|
110 |
| - force_sig_fault(SIGSEGV, 0, (void __user *)regs->pc); |
| 138 | + if (user_mode(regs)) { |
| 139 | + do_trap(regs, signo, code, addr); |
| 140 | + } else { |
| 141 | + if (!fixup_exception(regs)) |
| 142 | + die(regs, str); |
| 143 | + } |
111 | 144 | }
|
112 | 145 |
|
113 |
| -asmlinkage void trap_c(struct pt_regs *regs) |
114 |
| -{ |
115 |
| - int sig; |
116 |
| - unsigned long vector; |
117 |
| - siginfo_t info; |
118 |
| - struct task_struct *tsk = current; |
| 146 | +#define DO_ERROR_INFO(name, signo, code, str) \ |
| 147 | +asmlinkage __visible void name(struct pt_regs *regs) \ |
| 148 | +{ \ |
| 149 | + do_trap_error(regs, signo, code, regs->pc, "Oops - " str); \ |
| 150 | +} |
119 | 151 |
|
120 |
| - vector = (regs->sr >> 16) & 0xff; |
| 152 | +DO_ERROR_INFO(do_trap_unknown, |
| 153 | + SIGILL, ILL_ILLTRP, "unknown exception"); |
| 154 | +DO_ERROR_INFO(do_trap_zdiv, |
| 155 | + SIGFPE, FPE_INTDIV, "error zero div exception"); |
| 156 | +DO_ERROR_INFO(do_trap_buserr, |
| 157 | + SIGSEGV, ILL_ILLADR, "error bus error exception"); |
121 | 158 |
|
122 |
| - switch (vector) { |
123 |
| - case VEC_ZERODIV: |
124 |
| - die_if_kernel("Kernel mode ZERO DIV", regs, vector); |
125 |
| - sig = SIGFPE; |
126 |
| - break; |
127 |
| - /* ptrace */ |
128 |
| - case VEC_TRACE: |
| 159 | +asmlinkage void do_trap_misaligned(struct pt_regs *regs) |
| 160 | +{ |
| 161 | +#ifdef CONFIG_CPU_NEED_SOFTALIGN |
| 162 | + csky_alignment(regs); |
| 163 | +#else |
| 164 | + current->thread.trap_no = trap_no(regs); |
| 165 | + do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->pc, |
| 166 | + "Oops - load/store address misaligned"); |
| 167 | +#endif |
| 168 | +} |
| 169 | + |
| 170 | +asmlinkage void do_trap_bkpt(struct pt_regs *regs) |
| 171 | +{ |
129 | 172 | #ifdef CONFIG_KPROBES
|
130 |
| - if (kprobe_single_step_handler(regs)) |
131 |
| - return; |
| 173 | + if (kprobe_single_step_handler(regs)) |
| 174 | + return; |
132 | 175 | #endif
|
133 | 176 | #ifdef CONFIG_UPROBES
|
134 |
| - if (uprobe_single_step_handler(regs)) |
135 |
| - return; |
| 177 | + if (uprobe_single_step_handler(regs)) |
| 178 | + return; |
136 | 179 | #endif
|
137 |
| - info.si_code = TRAP_TRACE; |
138 |
| - sig = SIGTRAP; |
139 |
| - break; |
140 |
| - case VEC_ILLEGAL: |
141 |
| - tsk->thread.trap_no = vector; |
| 180 | + if (user_mode(regs)) { |
| 181 | + send_sig(SIGTRAP, current, 0); |
| 182 | + return; |
| 183 | + } |
| 184 | + |
| 185 | + do_trap_error(regs, SIGILL, ILL_ILLTRP, regs->pc, |
| 186 | + "Oops - illegal trap exception"); |
| 187 | +} |
| 188 | + |
| 189 | +asmlinkage void do_trap_illinsn(struct pt_regs *regs) |
| 190 | +{ |
| 191 | + current->thread.trap_no = trap_no(regs); |
| 192 | + |
142 | 193 | #ifdef CONFIG_KPROBES
|
143 |
| - if (kprobe_breakpoint_handler(regs)) |
144 |
| - return; |
| 194 | + if (kprobe_breakpoint_handler(regs)) |
| 195 | + return; |
145 | 196 | #endif
|
146 | 197 | #ifdef CONFIG_UPROBES
|
147 |
| - if (uprobe_breakpoint_handler(regs)) |
148 |
| - return; |
| 198 | + if (uprobe_breakpoint_handler(regs)) |
| 199 | + return; |
149 | 200 | #endif
|
150 |
| - die_if_kernel("Kernel mode ILLEGAL", regs, vector); |
151 | 201 | #ifndef CONFIG_CPU_NO_USER_BKPT
|
152 |
| - if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) |
| 202 | + if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) { |
| 203 | + send_sig(SIGTRAP, current, 0); |
| 204 | + return; |
| 205 | + } |
153 | 206 | #endif
|
154 |
| - { |
155 |
| - sig = SIGILL; |
156 |
| - break; |
157 |
| - } |
158 |
| - /* gdbserver breakpoint */ |
| 207 | + |
| 208 | + do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->pc, |
| 209 | + "Oops - illegal instruction exception"); |
| 210 | +} |
| 211 | + |
| 212 | +asmlinkage void do_trap_fpe(struct pt_regs *regs) |
| 213 | +{ |
| 214 | +#ifdef CONFIG_CPU_HAS_FP |
| 215 | + return fpu_fpe(regs); |
| 216 | +#else |
| 217 | + do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->pc, |
| 218 | + "Oops - fpu instruction exception"); |
| 219 | +#endif |
| 220 | +} |
| 221 | + |
| 222 | +asmlinkage void do_trap_priv(struct pt_regs *regs) |
| 223 | +{ |
| 224 | +#ifdef CONFIG_CPU_HAS_FP |
| 225 | + if (user_mode(regs) && fpu_libc_helper(regs)) |
| 226 | + return; |
| 227 | +#endif |
| 228 | + do_trap_error(regs, SIGILL, ILL_PRVOPC, regs->pc, |
| 229 | + "Oops - illegal privileged exception"); |
| 230 | +} |
| 231 | + |
| 232 | +asmlinkage void trap_c(struct pt_regs *regs) |
| 233 | +{ |
| 234 | + switch (trap_no(regs)) { |
| 235 | + case VEC_ZERODIV: |
| 236 | + do_trap_zdiv(regs); |
| 237 | + break; |
| 238 | + case VEC_TRACE: |
| 239 | + do_trap_bkpt(regs); |
| 240 | + break; |
| 241 | + case VEC_ILLEGAL: |
| 242 | + do_trap_illinsn(regs); |
| 243 | + break; |
159 | 244 | case VEC_TRAP1:
|
160 |
| - /* jtagserver breakpoint */ |
161 | 245 | case VEC_BREAKPOINT:
|
162 |
| - die_if_kernel("Kernel mode BKPT", regs, vector); |
163 |
| - info.si_code = TRAP_BRKPT; |
164 |
| - sig = SIGTRAP; |
| 246 | + do_trap_bkpt(regs); |
165 | 247 | break;
|
166 | 248 | case VEC_ACCESS:
|
167 |
| - tsk->thread.trap_no = vector; |
168 |
| - return buserr(regs); |
169 |
| -#ifdef CONFIG_CPU_NEED_SOFTALIGN |
| 249 | + do_trap_buserr(regs); |
| 250 | + break; |
170 | 251 | case VEC_ALIGN:
|
171 |
| - tsk->thread.trap_no = vector; |
172 |
| - return csky_alignment(regs); |
173 |
| -#endif |
174 |
| -#ifdef CONFIG_CPU_HAS_FPU |
| 252 | + do_trap_misaligned(regs); |
| 253 | + break; |
175 | 254 | case VEC_FPE:
|
176 |
| - tsk->thread.trap_no = vector; |
177 |
| - die_if_kernel("Kernel mode FPE", regs, vector); |
178 |
| - return fpu_fpe(regs); |
| 255 | + do_trap_fpe(regs); |
| 256 | + break; |
179 | 257 | case VEC_PRIV:
|
180 |
| - tsk->thread.trap_no = vector; |
181 |
| - die_if_kernel("Kernel mode PRIV", regs, vector); |
182 |
| - if (fpu_libc_helper(regs)) |
183 |
| - return; |
184 |
| -#endif |
| 258 | + do_trap_priv(regs); |
| 259 | + break; |
185 | 260 | default:
|
186 |
| - sig = SIGSEGV; |
| 261 | + do_trap_unknown(regs); |
187 | 262 | break;
|
188 | 263 | }
|
189 |
| - |
190 |
| - tsk->thread.trap_no = vector; |
191 |
| - |
192 |
| - send_sig(sig, current, 0); |
193 | 264 | }
|
0 commit comments