diff options
Diffstat (limited to 'arch/m68k/kernel/traps.c')
-rw-r--r-- | arch/m68k/kernel/traps.c | 1227 |
1 files changed, 1227 insertions, 0 deletions
diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c new file mode 100644 index 000000000000..deb36e8b04a2 --- /dev/null +++ b/arch/m68k/kernel/traps.c | |||
@@ -0,0 +1,1227 @@ | |||
1 | /* | ||
2 | * linux/arch/m68k/kernel/traps.c | ||
3 | * | ||
4 | * Copyright (C) 1993, 1994 by Hamish Macdonald | ||
5 | * | ||
6 | * 68040 fixes by Michael Rausch | ||
7 | * 68040 fixes by Martin Apel | ||
8 | * 68040 fixes and writeback by Richard Zidlicky | ||
9 | * 68060 fixes by Roman Hodek | ||
10 | * 68060 fixes by Jesper Skov | ||
11 | * | ||
12 | * This file is subject to the terms and conditions of the GNU General Public | ||
13 | * License. See the file COPYING in the main directory of this archive | ||
14 | * for more details. | ||
15 | */ | ||
16 | |||
17 | /* | ||
18 | * Sets up all exception vectors | ||
19 | */ | ||
20 | |||
21 | #include <linux/config.h> | ||
22 | #include <linux/sched.h> | ||
23 | #include <linux/signal.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/mm.h> | ||
26 | #include <linux/module.h> | ||
27 | #include <linux/a.out.h> | ||
28 | #include <linux/user.h> | ||
29 | #include <linux/string.h> | ||
30 | #include <linux/linkage.h> | ||
31 | #include <linux/init.h> | ||
32 | #include <linux/ptrace.h> | ||
33 | #include <linux/kallsyms.h> | ||
34 | |||
35 | #include <asm/setup.h> | ||
36 | #include <asm/fpu.h> | ||
37 | #include <asm/system.h> | ||
38 | #include <asm/uaccess.h> | ||
39 | #include <asm/traps.h> | ||
40 | #include <asm/pgalloc.h> | ||
41 | #include <asm/machdep.h> | ||
42 | #include <asm/siginfo.h> | ||
43 | |||
44 | /* assembler routines */ | ||
45 | asmlinkage void system_call(void); | ||
46 | asmlinkage void buserr(void); | ||
47 | asmlinkage void trap(void); | ||
48 | asmlinkage void inthandler(void); | ||
49 | asmlinkage void nmihandler(void); | ||
50 | #ifdef CONFIG_M68KFPU_EMU | ||
51 | asmlinkage void fpu_emu(void); | ||
52 | #endif | ||
53 | |||
54 | e_vector vectors[256] = { | ||
55 | [VEC_BUSERR] = buserr, | ||
56 | [VEC_ADDRERR] = trap, | ||
57 | [VEC_ILLEGAL] = trap, | ||
58 | [VEC_ZERODIV] = trap, | ||
59 | [VEC_CHK] = trap, | ||
60 | [VEC_TRAP] = trap, | ||
61 | [VEC_PRIV] = trap, | ||
62 | [VEC_TRACE] = trap, | ||
63 | [VEC_LINE10] = trap, | ||
64 | [VEC_LINE11] = trap, | ||
65 | [VEC_RESV12] = trap, | ||
66 | [VEC_COPROC] = trap, | ||
67 | [VEC_FORMAT] = trap, | ||
68 | [VEC_UNINT] = trap, | ||
69 | [VEC_RESV16] = trap, | ||
70 | [VEC_RESV17] = trap, | ||
71 | [VEC_RESV18] = trap, | ||
72 | [VEC_RESV19] = trap, | ||
73 | [VEC_RESV20] = trap, | ||
74 | [VEC_RESV21] = trap, | ||
75 | [VEC_RESV22] = trap, | ||
76 | [VEC_RESV23] = trap, | ||
77 | [VEC_SPUR] = inthandler, | ||
78 | [VEC_INT1] = inthandler, | ||
79 | [VEC_INT2] = inthandler, | ||
80 | [VEC_INT3] = inthandler, | ||
81 | [VEC_INT4] = inthandler, | ||
82 | [VEC_INT5] = inthandler, | ||
83 | [VEC_INT6] = inthandler, | ||
84 | [VEC_INT7] = inthandler, | ||
85 | [VEC_SYS] = system_call, | ||
86 | [VEC_TRAP1] = trap, | ||
87 | [VEC_TRAP2] = trap, | ||
88 | [VEC_TRAP3] = trap, | ||
89 | [VEC_TRAP4] = trap, | ||
90 | [VEC_TRAP5] = trap, | ||
91 | [VEC_TRAP6] = trap, | ||
92 | [VEC_TRAP7] = trap, | ||
93 | [VEC_TRAP8] = trap, | ||
94 | [VEC_TRAP9] = trap, | ||
95 | [VEC_TRAP10] = trap, | ||
96 | [VEC_TRAP11] = trap, | ||
97 | [VEC_TRAP12] = trap, | ||
98 | [VEC_TRAP13] = trap, | ||
99 | [VEC_TRAP14] = trap, | ||
100 | [VEC_TRAP15] = trap, | ||
101 | }; | ||
102 | |||
103 | /* nmi handler for the Amiga */ | ||
104 | asm(".text\n" | ||
105 | __ALIGN_STR "\n" | ||
106 | "nmihandler: rte"); | ||
107 | |||
108 | /* | ||
109 | * this must be called very early as the kernel might | ||
110 | * use some instruction that are emulated on the 060 | ||
111 | */ | ||
112 | void __init base_trap_init(void) | ||
113 | { | ||
114 | if(MACH_IS_SUN3X) { | ||
115 | extern e_vector *sun3x_prom_vbr; | ||
116 | |||
117 | __asm__ volatile ("movec %%vbr, %0" : "=r" ((void*)sun3x_prom_vbr)); | ||
118 | } | ||
119 | |||
120 | /* setup the exception vector table */ | ||
121 | __asm__ volatile ("movec %0,%%vbr" : : "r" ((void*)vectors)); | ||
122 | |||
123 | if (CPU_IS_060) { | ||
124 | /* set up ISP entry points */ | ||
125 | asmlinkage void unimp_vec(void) asm ("_060_isp_unimp"); | ||
126 | |||
127 | vectors[VEC_UNIMPII] = unimp_vec; | ||
128 | } | ||
129 | } | ||
130 | |||
131 | void __init trap_init (void) | ||
132 | { | ||
133 | int i; | ||
134 | |||
135 | for (i = 48; i < 64; i++) | ||
136 | if (!vectors[i]) | ||
137 | vectors[i] = trap; | ||
138 | |||
139 | for (i = 64; i < 256; i++) | ||
140 | vectors[i] = inthandler; | ||
141 | |||
142 | #ifdef CONFIG_M68KFPU_EMU | ||
143 | if (FPU_IS_EMU) | ||
144 | vectors[VEC_LINE11] = fpu_emu; | ||
145 | #endif | ||
146 | |||
147 | if (CPU_IS_040 && !FPU_IS_EMU) { | ||
148 | /* set up FPSP entry points */ | ||
149 | asmlinkage void dz_vec(void) asm ("dz"); | ||
150 | asmlinkage void inex_vec(void) asm ("inex"); | ||
151 | asmlinkage void ovfl_vec(void) asm ("ovfl"); | ||
152 | asmlinkage void unfl_vec(void) asm ("unfl"); | ||
153 | asmlinkage void snan_vec(void) asm ("snan"); | ||
154 | asmlinkage void operr_vec(void) asm ("operr"); | ||
155 | asmlinkage void bsun_vec(void) asm ("bsun"); | ||
156 | asmlinkage void fline_vec(void) asm ("fline"); | ||
157 | asmlinkage void unsupp_vec(void) asm ("unsupp"); | ||
158 | |||
159 | vectors[VEC_FPDIVZ] = dz_vec; | ||
160 | vectors[VEC_FPIR] = inex_vec; | ||
161 | vectors[VEC_FPOVER] = ovfl_vec; | ||
162 | vectors[VEC_FPUNDER] = unfl_vec; | ||
163 | vectors[VEC_FPNAN] = snan_vec; | ||
164 | vectors[VEC_FPOE] = operr_vec; | ||
165 | vectors[VEC_FPBRUC] = bsun_vec; | ||
166 | vectors[VEC_LINE11] = fline_vec; | ||
167 | vectors[VEC_FPUNSUP] = unsupp_vec; | ||
168 | } | ||
169 | |||
170 | if (CPU_IS_060 && !FPU_IS_EMU) { | ||
171 | /* set up IFPSP entry points */ | ||
172 | asmlinkage void snan_vec(void) asm ("_060_fpsp_snan"); | ||
173 | asmlinkage void operr_vec(void) asm ("_060_fpsp_operr"); | ||
174 | asmlinkage void ovfl_vec(void) asm ("_060_fpsp_ovfl"); | ||
175 | asmlinkage void unfl_vec(void) asm ("_060_fpsp_unfl"); | ||
176 | asmlinkage void dz_vec(void) asm ("_060_fpsp_dz"); | ||
177 | asmlinkage void inex_vec(void) asm ("_060_fpsp_inex"); | ||
178 | asmlinkage void fline_vec(void) asm ("_060_fpsp_fline"); | ||
179 | asmlinkage void unsupp_vec(void) asm ("_060_fpsp_unsupp"); | ||
180 | asmlinkage void effadd_vec(void) asm ("_060_fpsp_effadd"); | ||
181 | |||
182 | vectors[VEC_FPNAN] = snan_vec; | ||
183 | vectors[VEC_FPOE] = operr_vec; | ||
184 | vectors[VEC_FPOVER] = ovfl_vec; | ||
185 | vectors[VEC_FPUNDER] = unfl_vec; | ||
186 | vectors[VEC_FPDIVZ] = dz_vec; | ||
187 | vectors[VEC_FPIR] = inex_vec; | ||
188 | vectors[VEC_LINE11] = fline_vec; | ||
189 | vectors[VEC_FPUNSUP] = unsupp_vec; | ||
190 | vectors[VEC_UNIMPEA] = effadd_vec; | ||
191 | } | ||
192 | |||
193 | /* if running on an amiga, make the NMI interrupt do nothing */ | ||
194 | if (MACH_IS_AMIGA) { | ||
195 | vectors[VEC_INT7] = nmihandler; | ||
196 | } | ||
197 | } | ||
198 | |||
199 | |||
200 | static const char *vec_names[] = { | ||
201 | [VEC_RESETSP] = "RESET SP", | ||
202 | [VEC_RESETPC] = "RESET PC", | ||
203 | [VEC_BUSERR] = "BUS ERROR", | ||
204 | [VEC_ADDRERR] = "ADDRESS ERROR", | ||
205 | [VEC_ILLEGAL] = "ILLEGAL INSTRUCTION", | ||
206 | [VEC_ZERODIV] = "ZERO DIVIDE", | ||
207 | [VEC_CHK] = "CHK", | ||
208 | [VEC_TRAP] = "TRAPcc", | ||
209 | [VEC_PRIV] = "PRIVILEGE VIOLATION", | ||
210 | [VEC_TRACE] = "TRACE", | ||
211 | [VEC_LINE10] = "LINE 1010", | ||
212 | [VEC_LINE11] = "LINE 1111", | ||
213 | [VEC_RESV12] = "UNASSIGNED RESERVED 12", | ||
214 | [VEC_COPROC] = "COPROCESSOR PROTOCOL VIOLATION", | ||
215 | [VEC_FORMAT] = "FORMAT ERROR", | ||
216 | [VEC_UNINT] = "UNINITIALIZED INTERRUPT", | ||
217 | [VEC_RESV16] = "UNASSIGNED RESERVED 16", | ||
218 | [VEC_RESV17] = "UNASSIGNED RESERVED 17", | ||
219 | [VEC_RESV18] = "UNASSIGNED RESERVED 18", | ||
220 | [VEC_RESV19] = "UNASSIGNED RESERVED 19", | ||
221 | [VEC_RESV20] = "UNASSIGNED RESERVED 20", | ||
222 | [VEC_RESV21] = "UNASSIGNED RESERVED 21", | ||
223 | [VEC_RESV22] = "UNASSIGNED RESERVED 22", | ||
224 | [VEC_RESV23] = "UNASSIGNED RESERVED 23", | ||
225 | [VEC_SPUR] = "SPURIOUS INTERRUPT", | ||
226 | [VEC_INT1] = "LEVEL 1 INT", | ||
227 | [VEC_INT2] = "LEVEL 2 INT", | ||
228 | [VEC_INT3] = "LEVEL 3 INT", | ||
229 | [VEC_INT4] = "LEVEL 4 INT", | ||
230 | [VEC_INT5] = "LEVEL 5 INT", | ||
231 | [VEC_INT6] = "LEVEL 6 INT", | ||
232 | [VEC_INT7] = "LEVEL 7 INT", | ||
233 | [VEC_SYS] = "SYSCALL", | ||
234 | [VEC_TRAP1] = "TRAP #1", | ||
235 | [VEC_TRAP2] = "TRAP #2", | ||
236 | [VEC_TRAP3] = "TRAP #3", | ||
237 | [VEC_TRAP4] = "TRAP #4", | ||
238 | [VEC_TRAP5] = "TRAP #5", | ||
239 | [VEC_TRAP6] = "TRAP #6", | ||
240 | [VEC_TRAP7] = "TRAP #7", | ||
241 | [VEC_TRAP8] = "TRAP #8", | ||
242 | [VEC_TRAP9] = "TRAP #9", | ||
243 | [VEC_TRAP10] = "TRAP #10", | ||
244 | [VEC_TRAP11] = "TRAP #11", | ||
245 | [VEC_TRAP12] = "TRAP #12", | ||
246 | [VEC_TRAP13] = "TRAP #13", | ||
247 | [VEC_TRAP14] = "TRAP #14", | ||
248 | [VEC_TRAP15] = "TRAP #15", | ||
249 | [VEC_FPBRUC] = "FPCP BSUN", | ||
250 | [VEC_FPIR] = "FPCP INEXACT", | ||
251 | [VEC_FPDIVZ] = "FPCP DIV BY 0", | ||
252 | [VEC_FPUNDER] = "FPCP UNDERFLOW", | ||
253 | [VEC_FPOE] = "FPCP OPERAND ERROR", | ||
254 | [VEC_FPOVER] = "FPCP OVERFLOW", | ||
255 | [VEC_FPNAN] = "FPCP SNAN", | ||
256 | [VEC_FPUNSUP] = "FPCP UNSUPPORTED OPERATION", | ||
257 | [VEC_MMUCFG] = "MMU CONFIGURATION ERROR", | ||
258 | [VEC_MMUILL] = "MMU ILLEGAL OPERATION ERROR", | ||
259 | [VEC_MMUACC] = "MMU ACCESS LEVEL VIOLATION ERROR", | ||
260 | [VEC_RESV59] = "UNASSIGNED RESERVED 59", | ||
261 | [VEC_UNIMPEA] = "UNASSIGNED RESERVED 60", | ||
262 | [VEC_UNIMPII] = "UNASSIGNED RESERVED 61", | ||
263 | [VEC_RESV62] = "UNASSIGNED RESERVED 62", | ||
264 | [VEC_RESV63] = "UNASSIGNED RESERVED 63", | ||
265 | }; | ||
266 | |||
267 | static const char *space_names[] = { | ||
268 | [0] = "Space 0", | ||
269 | [USER_DATA] = "User Data", | ||
270 | [USER_PROGRAM] = "User Program", | ||
271 | #ifndef CONFIG_SUN3 | ||
272 | [3] = "Space 3", | ||
273 | #else | ||
274 | [FC_CONTROL] = "Control", | ||
275 | #endif | ||
276 | [4] = "Space 4", | ||
277 | [SUPER_DATA] = "Super Data", | ||
278 | [SUPER_PROGRAM] = "Super Program", | ||
279 | [CPU_SPACE] = "CPU" | ||
280 | }; | ||
281 | |||
282 | void die_if_kernel(char *,struct pt_regs *,int); | ||
283 | asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address, | ||
284 | unsigned long error_code); | ||
285 | int send_fault_sig(struct pt_regs *regs); | ||
286 | |||
287 | asmlinkage void trap_c(struct frame *fp); | ||
288 | |||
289 | #if defined (CONFIG_M68060) | ||
290 | static inline void access_error060 (struct frame *fp) | ||
291 | { | ||
292 | unsigned long fslw = fp->un.fmt4.pc; /* is really FSLW for access error */ | ||
293 | |||
294 | #ifdef DEBUG | ||
295 | printk("fslw=%#lx, fa=%#lx\n", fslw, fp->un.fmt4.effaddr); | ||
296 | #endif | ||
297 | |||
298 | if (fslw & MMU060_BPE) { | ||
299 | /* branch prediction error -> clear branch cache */ | ||
300 | __asm__ __volatile__ ("movec %/cacr,%/d0\n\t" | ||
301 | "orl #0x00400000,%/d0\n\t" | ||
302 | "movec %/d0,%/cacr" | ||
303 | : : : "d0" ); | ||
304 | /* return if there's no other error */ | ||
305 | if (!(fslw & MMU060_ERR_BITS) && !(fslw & MMU060_SEE)) | ||
306 | return; | ||
307 | } | ||
308 | |||
309 | if (fslw & (MMU060_DESC_ERR | MMU060_WP | MMU060_SP)) { | ||
310 | unsigned long errorcode; | ||
311 | unsigned long addr = fp->un.fmt4.effaddr; | ||
312 | |||
313 | if (fslw & MMU060_MA) | ||
314 | addr = (addr + PAGE_SIZE - 1) & PAGE_MASK; | ||
315 | |||
316 | errorcode = 1; | ||
317 | if (fslw & MMU060_DESC_ERR) { | ||
318 | __flush_tlb040_one(addr); | ||
319 | errorcode = 0; | ||
320 | } | ||
321 | if (fslw & MMU060_W) | ||
322 | errorcode |= 2; | ||
323 | #ifdef DEBUG | ||
324 | printk("errorcode = %d\n", errorcode ); | ||
325 | #endif | ||
326 | do_page_fault(&fp->ptregs, addr, errorcode); | ||
327 | } else if (fslw & (MMU060_SEE)){ | ||
328 | /* Software Emulation Error. | ||
329 | * fault during mem_read/mem_write in ifpsp060/os.S | ||
330 | */ | ||
331 | send_fault_sig(&fp->ptregs); | ||
332 | } else if (!(fslw & (MMU060_RE|MMU060_WE)) || | ||
333 | send_fault_sig(&fp->ptregs) > 0) { | ||
334 | printk("pc=%#lx, fa=%#lx\n", fp->ptregs.pc, fp->un.fmt4.effaddr); | ||
335 | printk( "68060 access error, fslw=%lx\n", fslw ); | ||
336 | trap_c( fp ); | ||
337 | } | ||
338 | } | ||
339 | #endif /* CONFIG_M68060 */ | ||
340 | |||
341 | #if defined (CONFIG_M68040) | ||
342 | static inline unsigned long probe040(int iswrite, unsigned long addr, int wbs) | ||
343 | { | ||
344 | unsigned long mmusr; | ||
345 | mm_segment_t old_fs = get_fs(); | ||
346 | |||
347 | set_fs(MAKE_MM_SEG(wbs)); | ||
348 | |||
349 | if (iswrite) | ||
350 | asm volatile (".chip 68040; ptestw (%0); .chip 68k" : : "a" (addr)); | ||
351 | else | ||
352 | asm volatile (".chip 68040; ptestr (%0); .chip 68k" : : "a" (addr)); | ||
353 | |||
354 | asm volatile (".chip 68040; movec %%mmusr,%0; .chip 68k" : "=r" (mmusr)); | ||
355 | |||
356 | set_fs(old_fs); | ||
357 | |||
358 | return mmusr; | ||
359 | } | ||
360 | |||
361 | static inline int do_040writeback1(unsigned short wbs, unsigned long wba, | ||
362 | unsigned long wbd) | ||
363 | { | ||
364 | int res = 0; | ||
365 | mm_segment_t old_fs = get_fs(); | ||
366 | |||
367 | /* set_fs can not be moved, otherwise put_user() may oops */ | ||
368 | set_fs(MAKE_MM_SEG(wbs)); | ||
369 | |||
370 | switch (wbs & WBSIZ_040) { | ||
371 | case BA_SIZE_BYTE: | ||
372 | res = put_user(wbd & 0xff, (char *)wba); | ||
373 | break; | ||
374 | case BA_SIZE_WORD: | ||
375 | res = put_user(wbd & 0xffff, (short *)wba); | ||
376 | break; | ||
377 | case BA_SIZE_LONG: | ||
378 | res = put_user(wbd, (int *)wba); | ||
379 | break; | ||
380 | } | ||
381 | |||
382 | /* set_fs can not be moved, otherwise put_user() may oops */ | ||
383 | set_fs(old_fs); | ||
384 | |||
385 | |||
386 | #ifdef DEBUG | ||
387 | printk("do_040writeback1, res=%d\n",res); | ||
388 | #endif | ||
389 | |||
390 | return res; | ||
391 | } | ||
392 | |||
393 | /* after an exception in a writeback the stack frame corresponding | ||
394 | * to that exception is discarded, set a few bits in the old frame | ||
395 | * to simulate what it should look like | ||
396 | */ | ||
397 | static inline void fix_xframe040(struct frame *fp, unsigned long wba, unsigned short wbs) | ||
398 | { | ||
399 | fp->un.fmt7.faddr = wba; | ||
400 | fp->un.fmt7.ssw = wbs & 0xff; | ||
401 | if (wba != current->thread.faddr) | ||
402 | fp->un.fmt7.ssw |= MA_040; | ||
403 | } | ||
404 | |||
405 | static inline void do_040writebacks(struct frame *fp) | ||
406 | { | ||
407 | int res = 0; | ||
408 | #if 0 | ||
409 | if (fp->un.fmt7.wb1s & WBV_040) | ||
410 | printk("access_error040: cannot handle 1st writeback. oops.\n"); | ||
411 | #endif | ||
412 | |||
413 | if ((fp->un.fmt7.wb2s & WBV_040) && | ||
414 | !(fp->un.fmt7.wb2s & WBTT_040)) { | ||
415 | res = do_040writeback1(fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, | ||
416 | fp->un.fmt7.wb2d); | ||
417 | if (res) | ||
418 | fix_xframe040(fp, fp->un.fmt7.wb2a, fp->un.fmt7.wb2s); | ||
419 | else | ||
420 | fp->un.fmt7.wb2s = 0; | ||
421 | } | ||
422 | |||
423 | /* do the 2nd wb only if the first one was successful (except for a kernel wb) */ | ||
424 | if (fp->un.fmt7.wb3s & WBV_040 && (!res || fp->un.fmt7.wb3s & 4)) { | ||
425 | res = do_040writeback1(fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, | ||
426 | fp->un.fmt7.wb3d); | ||
427 | if (res) | ||
428 | { | ||
429 | fix_xframe040(fp, fp->un.fmt7.wb3a, fp->un.fmt7.wb3s); | ||
430 | |||
431 | fp->un.fmt7.wb2s = fp->un.fmt7.wb3s; | ||
432 | fp->un.fmt7.wb3s &= (~WBV_040); | ||
433 | fp->un.fmt7.wb2a = fp->un.fmt7.wb3a; | ||
434 | fp->un.fmt7.wb2d = fp->un.fmt7.wb3d; | ||
435 | } | ||
436 | else | ||
437 | fp->un.fmt7.wb3s = 0; | ||
438 | } | ||
439 | |||
440 | if (res) | ||
441 | send_fault_sig(&fp->ptregs); | ||
442 | } | ||
443 | |||
444 | /* | ||
445 | * called from sigreturn(), must ensure userspace code didn't | ||
446 | * manipulate exception frame to circumvent protection, then complete | ||
447 | * pending writebacks | ||
448 | * we just clear TM2 to turn it into an userspace access | ||
449 | */ | ||
450 | asmlinkage void berr_040cleanup(struct frame *fp) | ||
451 | { | ||
452 | fp->un.fmt7.wb2s &= ~4; | ||
453 | fp->un.fmt7.wb3s &= ~4; | ||
454 | |||
455 | do_040writebacks(fp); | ||
456 | } | ||
457 | |||
458 | static inline void access_error040(struct frame *fp) | ||
459 | { | ||
460 | unsigned short ssw = fp->un.fmt7.ssw; | ||
461 | unsigned long mmusr; | ||
462 | |||
463 | #ifdef DEBUG | ||
464 | printk("ssw=%#x, fa=%#lx\n", ssw, fp->un.fmt7.faddr); | ||
465 | printk("wb1s=%#x, wb2s=%#x, wb3s=%#x\n", fp->un.fmt7.wb1s, | ||
466 | fp->un.fmt7.wb2s, fp->un.fmt7.wb3s); | ||
467 | printk ("wb2a=%lx, wb3a=%lx, wb2d=%lx, wb3d=%lx\n", | ||
468 | fp->un.fmt7.wb2a, fp->un.fmt7.wb3a, | ||
469 | fp->un.fmt7.wb2d, fp->un.fmt7.wb3d); | ||
470 | #endif | ||
471 | |||
472 | if (ssw & ATC_040) { | ||
473 | unsigned long addr = fp->un.fmt7.faddr; | ||
474 | unsigned long errorcode; | ||
475 | |||
476 | /* | ||
477 | * The MMU status has to be determined AFTER the address | ||
478 | * has been corrected if there was a misaligned access (MA). | ||
479 | */ | ||
480 | if (ssw & MA_040) | ||
481 | addr = (addr + 7) & -8; | ||
482 | |||
483 | /* MMU error, get the MMUSR info for this access */ | ||
484 | mmusr = probe040(!(ssw & RW_040), addr, ssw); | ||
485 | #ifdef DEBUG | ||
486 | printk("mmusr = %lx\n", mmusr); | ||
487 | #endif | ||
488 | errorcode = 1; | ||
489 | if (!(mmusr & MMU_R_040)) { | ||
490 | /* clear the invalid atc entry */ | ||
491 | __flush_tlb040_one(addr); | ||
492 | errorcode = 0; | ||
493 | } | ||
494 | |||
495 | /* despite what documentation seems to say, RMW | ||
496 | * accesses have always both the LK and RW bits set */ | ||
497 | if (!(ssw & RW_040) || (ssw & LK_040)) | ||
498 | errorcode |= 2; | ||
499 | |||
500 | if (do_page_fault(&fp->ptregs, addr, errorcode)) { | ||
501 | #ifdef DEBUG | ||
502 | printk("do_page_fault() !=0 \n"); | ||
503 | #endif | ||
504 | if (user_mode(&fp->ptregs)){ | ||
505 | /* delay writebacks after signal delivery */ | ||
506 | #ifdef DEBUG | ||
507 | printk(".. was usermode - return\n"); | ||
508 | #endif | ||
509 | return; | ||
510 | } | ||
511 | /* disable writeback into user space from kernel | ||
512 | * (if do_page_fault didn't fix the mapping, | ||
513 | * the writeback won't do good) | ||
514 | */ | ||
515 | #ifdef DEBUG | ||
516 | printk(".. disabling wb2\n"); | ||
517 | #endif | ||
518 | if (fp->un.fmt7.wb2a == fp->un.fmt7.faddr) | ||
519 | fp->un.fmt7.wb2s &= ~WBV_040; | ||
520 | } | ||
521 | } else if (send_fault_sig(&fp->ptregs) > 0) { | ||
522 | printk("68040 access error, ssw=%x\n", ssw); | ||
523 | trap_c(fp); | ||
524 | } | ||
525 | |||
526 | do_040writebacks(fp); | ||
527 | } | ||
528 | #endif /* CONFIG_M68040 */ | ||
529 | |||
530 | #if defined(CONFIG_SUN3) | ||
531 | #include <asm/sun3mmu.h> | ||
532 | |||
533 | extern int mmu_emu_handle_fault (unsigned long, int, int); | ||
534 | |||
535 | /* sun3 version of bus_error030 */ | ||
536 | |||
537 | static inline void bus_error030 (struct frame *fp) | ||
538 | { | ||
539 | unsigned char buserr_type = sun3_get_buserr (); | ||
540 | unsigned long addr, errorcode; | ||
541 | unsigned short ssw = fp->un.fmtb.ssw; | ||
542 | extern unsigned long _sun3_map_test_start, _sun3_map_test_end; | ||
543 | |||
544 | #ifdef DEBUG | ||
545 | if (ssw & (FC | FB)) | ||
546 | printk ("Instruction fault at %#010lx\n", | ||
547 | ssw & FC ? | ||
548 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 | ||
549 | : | ||
550 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
551 | if (ssw & DF) | ||
552 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
553 | ssw & RW ? "read" : "write", | ||
554 | fp->un.fmtb.daddr, | ||
555 | space_names[ssw & DFC], fp->ptregs.pc); | ||
556 | #endif | ||
557 | |||
558 | /* | ||
559 | * Check if this page should be demand-mapped. This needs to go before | ||
560 | * the testing for a bad kernel-space access (demand-mapping applies | ||
561 | * to kernel accesses too). | ||
562 | */ | ||
563 | |||
564 | if ((ssw & DF) | ||
565 | && (buserr_type & (SUN3_BUSERR_PROTERR | SUN3_BUSERR_INVALID))) { | ||
566 | if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 0)) | ||
567 | return; | ||
568 | } | ||
569 | |||
570 | /* Check for kernel-space pagefault (BAD). */ | ||
571 | if (fp->ptregs.sr & PS_S) { | ||
572 | /* kernel fault must be a data fault to user space */ | ||
573 | if (! ((ssw & DF) && ((ssw & DFC) == USER_DATA))) { | ||
574 | // try checking the kernel mappings before surrender | ||
575 | if (mmu_emu_handle_fault (fp->un.fmtb.daddr, ssw & RW, 1)) | ||
576 | return; | ||
577 | /* instruction fault or kernel data fault! */ | ||
578 | if (ssw & (FC | FB)) | ||
579 | printk ("Instruction fault at %#010lx\n", | ||
580 | fp->ptregs.pc); | ||
581 | if (ssw & DF) { | ||
582 | /* was this fault incurred testing bus mappings? */ | ||
583 | if((fp->ptregs.pc >= (unsigned long)&_sun3_map_test_start) && | ||
584 | (fp->ptregs.pc <= (unsigned long)&_sun3_map_test_end)) { | ||
585 | send_fault_sig(&fp->ptregs); | ||
586 | return; | ||
587 | } | ||
588 | |||
589 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
590 | ssw & RW ? "read" : "write", | ||
591 | fp->un.fmtb.daddr, | ||
592 | space_names[ssw & DFC], fp->ptregs.pc); | ||
593 | } | ||
594 | printk ("BAD KERNEL BUSERR\n"); | ||
595 | |||
596 | die_if_kernel("Oops", &fp->ptregs,0); | ||
597 | force_sig(SIGKILL, current); | ||
598 | return; | ||
599 | } | ||
600 | } else { | ||
601 | /* user fault */ | ||
602 | if (!(ssw & (FC | FB)) && !(ssw & DF)) | ||
603 | /* not an instruction fault or data fault! BAD */ | ||
604 | panic ("USER BUSERR w/o instruction or data fault"); | ||
605 | } | ||
606 | |||
607 | |||
608 | /* First handle the data fault, if any. */ | ||
609 | if (ssw & DF) { | ||
610 | addr = fp->un.fmtb.daddr; | ||
611 | |||
612 | // errorcode bit 0: 0 -> no page 1 -> protection fault | ||
613 | // errorcode bit 1: 0 -> read fault 1 -> write fault | ||
614 | |||
615 | // (buserr_type & SUN3_BUSERR_PROTERR) -> protection fault | ||
616 | // (buserr_type & SUN3_BUSERR_INVALID) -> invalid page fault | ||
617 | |||
618 | if (buserr_type & SUN3_BUSERR_PROTERR) | ||
619 | errorcode = 0x01; | ||
620 | else if (buserr_type & SUN3_BUSERR_INVALID) | ||
621 | errorcode = 0x00; | ||
622 | else { | ||
623 | #ifdef DEBUG | ||
624 | printk ("*** unexpected busfault type=%#04x\n", buserr_type); | ||
625 | printk ("invalid %s access at %#lx from pc %#lx\n", | ||
626 | !(ssw & RW) ? "write" : "read", addr, | ||
627 | fp->ptregs.pc); | ||
628 | #endif | ||
629 | die_if_kernel ("Oops", &fp->ptregs, buserr_type); | ||
630 | force_sig (SIGBUS, current); | ||
631 | return; | ||
632 | } | ||
633 | |||
634 | //todo: wtf is RM bit? --m | ||
635 | if (!(ssw & RW) || ssw & RM) | ||
636 | errorcode |= 0x02; | ||
637 | |||
638 | /* Handle page fault. */ | ||
639 | do_page_fault (&fp->ptregs, addr, errorcode); | ||
640 | |||
641 | /* Retry the data fault now. */ | ||
642 | return; | ||
643 | } | ||
644 | |||
645 | /* Now handle the instruction fault. */ | ||
646 | |||
647 | /* Get the fault address. */ | ||
648 | if (fp->ptregs.format == 0xA) | ||
649 | addr = fp->ptregs.pc + 4; | ||
650 | else | ||
651 | addr = fp->un.fmtb.baddr; | ||
652 | if (ssw & FC) | ||
653 | addr -= 2; | ||
654 | |||
655 | if (buserr_type & SUN3_BUSERR_INVALID) { | ||
656 | if (!mmu_emu_handle_fault (fp->un.fmtb.daddr, 1, 0)) | ||
657 | do_page_fault (&fp->ptregs, addr, 0); | ||
658 | } else { | ||
659 | #ifdef DEBUG | ||
660 | printk ("protection fault on insn access (segv).\n"); | ||
661 | #endif | ||
662 | force_sig (SIGSEGV, current); | ||
663 | } | ||
664 | } | ||
665 | #else | ||
666 | #if defined(CPU_M68020_OR_M68030) | ||
667 | static inline void bus_error030 (struct frame *fp) | ||
668 | { | ||
669 | volatile unsigned short temp; | ||
670 | unsigned short mmusr; | ||
671 | unsigned long addr, errorcode; | ||
672 | unsigned short ssw = fp->un.fmtb.ssw; | ||
673 | #ifdef DEBUG | ||
674 | unsigned long desc; | ||
675 | |||
676 | printk ("pid = %x ", current->pid); | ||
677 | printk ("SSW=%#06x ", ssw); | ||
678 | |||
679 | if (ssw & (FC | FB)) | ||
680 | printk ("Instruction fault at %#010lx\n", | ||
681 | ssw & FC ? | ||
682 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2 | ||
683 | : | ||
684 | fp->ptregs.format == 0xa ? fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
685 | if (ssw & DF) | ||
686 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
687 | ssw & RW ? "read" : "write", | ||
688 | fp->un.fmtb.daddr, | ||
689 | space_names[ssw & DFC], fp->ptregs.pc); | ||
690 | #endif | ||
691 | |||
692 | /* ++andreas: If a data fault and an instruction fault happen | ||
693 | at the same time map in both pages. */ | ||
694 | |||
695 | /* First handle the data fault, if any. */ | ||
696 | if (ssw & DF) { | ||
697 | addr = fp->un.fmtb.daddr; | ||
698 | |||
699 | #ifdef DEBUG | ||
700 | asm volatile ("ptestr %3,%2@,#7,%0\n\t" | ||
701 | "pmove %%psr,%1@" | ||
702 | : "=a&" (desc) | ||
703 | : "a" (&temp), "a" (addr), "d" (ssw)); | ||
704 | #else | ||
705 | asm volatile ("ptestr %2,%1@,#7\n\t" | ||
706 | "pmove %%psr,%0@" | ||
707 | : : "a" (&temp), "a" (addr), "d" (ssw)); | ||
708 | #endif | ||
709 | mmusr = temp; | ||
710 | |||
711 | #ifdef DEBUG | ||
712 | printk("mmusr is %#x for addr %#lx in task %p\n", | ||
713 | mmusr, addr, current); | ||
714 | printk("descriptor address is %#lx, contents %#lx\n", | ||
715 | __va(desc), *(unsigned long *)__va(desc)); | ||
716 | #endif | ||
717 | |||
718 | errorcode = (mmusr & MMU_I) ? 0 : 1; | ||
719 | if (!(ssw & RW) || (ssw & RM)) | ||
720 | errorcode |= 2; | ||
721 | |||
722 | if (mmusr & (MMU_I | MMU_WP)) { | ||
723 | if (ssw & 4) { | ||
724 | printk("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
725 | ssw & RW ? "read" : "write", | ||
726 | fp->un.fmtb.daddr, | ||
727 | space_names[ssw & DFC], fp->ptregs.pc); | ||
728 | goto buserr; | ||
729 | } | ||
730 | /* Don't try to do anything further if an exception was | ||
731 | handled. */ | ||
732 | if (do_page_fault (&fp->ptregs, addr, errorcode) < 0) | ||
733 | return; | ||
734 | } else if (!(mmusr & MMU_I)) { | ||
735 | /* probably a 020 cas fault */ | ||
736 | if (!(ssw & RM) && send_fault_sig(&fp->ptregs) > 0) | ||
737 | printk("unexpected bus error (%#x,%#x)\n", ssw, mmusr); | ||
738 | } else if (mmusr & (MMU_B|MMU_L|MMU_S)) { | ||
739 | printk("invalid %s access at %#lx from pc %#lx\n", | ||
740 | !(ssw & RW) ? "write" : "read", addr, | ||
741 | fp->ptregs.pc); | ||
742 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
743 | force_sig(SIGSEGV, current); | ||
744 | return; | ||
745 | } else { | ||
746 | #if 0 | ||
747 | static volatile long tlong; | ||
748 | #endif | ||
749 | |||
750 | printk("weird %s access at %#lx from pc %#lx (ssw is %#x)\n", | ||
751 | !(ssw & RW) ? "write" : "read", addr, | ||
752 | fp->ptregs.pc, ssw); | ||
753 | asm volatile ("ptestr #1,%1@,#0\n\t" | ||
754 | "pmove %%psr,%0@" | ||
755 | : /* no outputs */ | ||
756 | : "a" (&temp), "a" (addr)); | ||
757 | mmusr = temp; | ||
758 | |||
759 | printk ("level 0 mmusr is %#x\n", mmusr); | ||
760 | #if 0 | ||
761 | asm volatile ("pmove %%tt0,%0@" | ||
762 | : /* no outputs */ | ||
763 | : "a" (&tlong)); | ||
764 | printk("tt0 is %#lx, ", tlong); | ||
765 | asm volatile ("pmove %%tt1,%0@" | ||
766 | : /* no outputs */ | ||
767 | : "a" (&tlong)); | ||
768 | printk("tt1 is %#lx\n", tlong); | ||
769 | #endif | ||
770 | #ifdef DEBUG | ||
771 | printk("Unknown SIGSEGV - 1\n"); | ||
772 | #endif | ||
773 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
774 | force_sig(SIGSEGV, current); | ||
775 | return; | ||
776 | } | ||
777 | |||
778 | /* setup an ATC entry for the access about to be retried */ | ||
779 | if (!(ssw & RW) || (ssw & RM)) | ||
780 | asm volatile ("ploadw %1,%0@" : /* no outputs */ | ||
781 | : "a" (addr), "d" (ssw)); | ||
782 | else | ||
783 | asm volatile ("ploadr %1,%0@" : /* no outputs */ | ||
784 | : "a" (addr), "d" (ssw)); | ||
785 | } | ||
786 | |||
787 | /* Now handle the instruction fault. */ | ||
788 | |||
789 | if (!(ssw & (FC|FB))) | ||
790 | return; | ||
791 | |||
792 | if (fp->ptregs.sr & PS_S) { | ||
793 | printk("Instruction fault at %#010lx\n", | ||
794 | fp->ptregs.pc); | ||
795 | buserr: | ||
796 | printk ("BAD KERNEL BUSERR\n"); | ||
797 | die_if_kernel("Oops",&fp->ptregs,0); | ||
798 | force_sig(SIGKILL, current); | ||
799 | return; | ||
800 | } | ||
801 | |||
802 | /* get the fault address */ | ||
803 | if (fp->ptregs.format == 10) | ||
804 | addr = fp->ptregs.pc + 4; | ||
805 | else | ||
806 | addr = fp->un.fmtb.baddr; | ||
807 | if (ssw & FC) | ||
808 | addr -= 2; | ||
809 | |||
810 | if ((ssw & DF) && ((addr ^ fp->un.fmtb.daddr) & PAGE_MASK) == 0) | ||
811 | /* Insn fault on same page as data fault. But we | ||
812 | should still create the ATC entry. */ | ||
813 | goto create_atc_entry; | ||
814 | |||
815 | #ifdef DEBUG | ||
816 | asm volatile ("ptestr #1,%2@,#7,%0\n\t" | ||
817 | "pmove %%psr,%1@" | ||
818 | : "=a&" (desc) | ||
819 | : "a" (&temp), "a" (addr)); | ||
820 | #else | ||
821 | asm volatile ("ptestr #1,%1@,#7\n\t" | ||
822 | "pmove %%psr,%0@" | ||
823 | : : "a" (&temp), "a" (addr)); | ||
824 | #endif | ||
825 | mmusr = temp; | ||
826 | |||
827 | #ifdef DEBUG | ||
828 | printk ("mmusr is %#x for addr %#lx in task %p\n", | ||
829 | mmusr, addr, current); | ||
830 | printk ("descriptor address is %#lx, contents %#lx\n", | ||
831 | __va(desc), *(unsigned long *)__va(desc)); | ||
832 | #endif | ||
833 | |||
834 | if (mmusr & MMU_I) | ||
835 | do_page_fault (&fp->ptregs, addr, 0); | ||
836 | else if (mmusr & (MMU_B|MMU_L|MMU_S)) { | ||
837 | printk ("invalid insn access at %#lx from pc %#lx\n", | ||
838 | addr, fp->ptregs.pc); | ||
839 | #ifdef DEBUG | ||
840 | printk("Unknown SIGSEGV - 2\n"); | ||
841 | #endif | ||
842 | die_if_kernel("Oops",&fp->ptregs,mmusr); | ||
843 | force_sig(SIGSEGV, current); | ||
844 | return; | ||
845 | } | ||
846 | |||
847 | create_atc_entry: | ||
848 | /* setup an ATC entry for the access about to be retried */ | ||
849 | asm volatile ("ploadr #2,%0@" : /* no outputs */ | ||
850 | : "a" (addr)); | ||
851 | } | ||
852 | #endif /* CPU_M68020_OR_M68030 */ | ||
853 | #endif /* !CONFIG_SUN3 */ | ||
854 | |||
855 | asmlinkage void buserr_c(struct frame *fp) | ||
856 | { | ||
857 | /* Only set esp0 if coming from user mode */ | ||
858 | if (user_mode(&fp->ptregs)) | ||
859 | current->thread.esp0 = (unsigned long) fp; | ||
860 | |||
861 | #ifdef DEBUG | ||
862 | printk ("*** Bus Error *** Format is %x\n", fp->ptregs.format); | ||
863 | #endif | ||
864 | |||
865 | switch (fp->ptregs.format) { | ||
866 | #if defined (CONFIG_M68060) | ||
867 | case 4: /* 68060 access error */ | ||
868 | access_error060 (fp); | ||
869 | break; | ||
870 | #endif | ||
871 | #if defined (CONFIG_M68040) | ||
872 | case 0x7: /* 68040 access error */ | ||
873 | access_error040 (fp); | ||
874 | break; | ||
875 | #endif | ||
876 | #if defined (CPU_M68020_OR_M68030) | ||
877 | case 0xa: | ||
878 | case 0xb: | ||
879 | bus_error030 (fp); | ||
880 | break; | ||
881 | #endif | ||
882 | default: | ||
883 | die_if_kernel("bad frame format",&fp->ptregs,0); | ||
884 | #ifdef DEBUG | ||
885 | printk("Unknown SIGSEGV - 4\n"); | ||
886 | #endif | ||
887 | force_sig(SIGSEGV, current); | ||
888 | } | ||
889 | } | ||
890 | |||
891 | |||
892 | static int kstack_depth_to_print = 48; | ||
893 | |||
894 | void show_trace(unsigned long *stack) | ||
895 | { | ||
896 | unsigned long *endstack; | ||
897 | unsigned long addr; | ||
898 | int i; | ||
899 | |||
900 | printk("Call Trace:"); | ||
901 | addr = (unsigned long)stack + THREAD_SIZE - 1; | ||
902 | endstack = (unsigned long *)(addr & -THREAD_SIZE); | ||
903 | i = 0; | ||
904 | while (stack + 1 <= endstack) { | ||
905 | addr = *stack++; | ||
906 | /* | ||
907 | * If the address is either in the text segment of the | ||
908 | * kernel, or in the region which contains vmalloc'ed | ||
909 | * memory, it *may* be the address of a calling | ||
910 | * routine; if so, print it so that someone tracing | ||
911 | * down the cause of the crash will be able to figure | ||
912 | * out the call path that was taken. | ||
913 | */ | ||
914 | if (__kernel_text_address(addr)) { | ||
915 | #ifndef CONFIG_KALLSYMS | ||
916 | if (i % 5 == 0) | ||
917 | printk("\n "); | ||
918 | #endif | ||
919 | printk(" [<%08lx>]", addr); | ||
920 | print_symbol(" %s\n", addr); | ||
921 | i++; | ||
922 | } | ||
923 | } | ||
924 | printk("\n"); | ||
925 | } | ||
926 | |||
927 | void show_registers(struct pt_regs *regs) | ||
928 | { | ||
929 | struct frame *fp = (struct frame *)regs; | ||
930 | unsigned long addr; | ||
931 | int i; | ||
932 | |||
933 | addr = (unsigned long)&fp->un; | ||
934 | printk("Frame format=%X ", fp->ptregs.format); | ||
935 | switch (fp->ptregs.format) { | ||
936 | case 0x2: | ||
937 | printk("instr addr=%08lx\n", fp->un.fmt2.iaddr); | ||
938 | addr += sizeof(fp->un.fmt2); | ||
939 | break; | ||
940 | case 0x3: | ||
941 | printk("eff addr=%08lx\n", fp->un.fmt3.effaddr); | ||
942 | addr += sizeof(fp->un.fmt3); | ||
943 | break; | ||
944 | case 0x4: | ||
945 | printk((CPU_IS_060 ? "fault addr=%08lx fslw=%08lx\n" | ||
946 | : "eff addr=%08lx pc=%08lx\n"), | ||
947 | fp->un.fmt4.effaddr, fp->un.fmt4.pc); | ||
948 | addr += sizeof(fp->un.fmt4); | ||
949 | break; | ||
950 | case 0x7: | ||
951 | printk("eff addr=%08lx ssw=%04x faddr=%08lx\n", | ||
952 | fp->un.fmt7.effaddr, fp->un.fmt7.ssw, fp->un.fmt7.faddr); | ||
953 | printk("wb 1 stat/addr/data: %04x %08lx %08lx\n", | ||
954 | fp->un.fmt7.wb1s, fp->un.fmt7.wb1a, fp->un.fmt7.wb1dpd0); | ||
955 | printk("wb 2 stat/addr/data: %04x %08lx %08lx\n", | ||
956 | fp->un.fmt7.wb2s, fp->un.fmt7.wb2a, fp->un.fmt7.wb2d); | ||
957 | printk("wb 3 stat/addr/data: %04x %08lx %08lx\n", | ||
958 | fp->un.fmt7.wb3s, fp->un.fmt7.wb3a, fp->un.fmt7.wb3d); | ||
959 | printk("push data: %08lx %08lx %08lx %08lx\n", | ||
960 | fp->un.fmt7.wb1dpd0, fp->un.fmt7.pd1, fp->un.fmt7.pd2, | ||
961 | fp->un.fmt7.pd3); | ||
962 | addr += sizeof(fp->un.fmt7); | ||
963 | break; | ||
964 | case 0x9: | ||
965 | printk("instr addr=%08lx\n", fp->un.fmt9.iaddr); | ||
966 | addr += sizeof(fp->un.fmt9); | ||
967 | break; | ||
968 | case 0xa: | ||
969 | printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", | ||
970 | fp->un.fmta.ssw, fp->un.fmta.isc, fp->un.fmta.isb, | ||
971 | fp->un.fmta.daddr, fp->un.fmta.dobuf); | ||
972 | addr += sizeof(fp->un.fmta); | ||
973 | break; | ||
974 | case 0xb: | ||
975 | printk("ssw=%04x isc=%04x isb=%04x daddr=%08lx dobuf=%08lx\n", | ||
976 | fp->un.fmtb.ssw, fp->un.fmtb.isc, fp->un.fmtb.isb, | ||
977 | fp->un.fmtb.daddr, fp->un.fmtb.dobuf); | ||
978 | printk("baddr=%08lx dibuf=%08lx ver=%x\n", | ||
979 | fp->un.fmtb.baddr, fp->un.fmtb.dibuf, fp->un.fmtb.ver); | ||
980 | addr += sizeof(fp->un.fmtb); | ||
981 | break; | ||
982 | default: | ||
983 | printk("\n"); | ||
984 | } | ||
985 | show_stack(NULL, (unsigned long *)addr); | ||
986 | |||
987 | printk("Code: "); | ||
988 | for (i = 0; i < 10; i++) | ||
989 | printk("%04x ", 0xffff & ((short *) fp->ptregs.pc)[i]); | ||
990 | printk ("\n"); | ||
991 | } | ||
992 | |||
993 | void show_stack(struct task_struct *task, unsigned long *stack) | ||
994 | { | ||
995 | unsigned long *endstack; | ||
996 | int i; | ||
997 | |||
998 | if (!stack) { | ||
999 | if (task) | ||
1000 | stack = (unsigned long *)task->thread.esp0; | ||
1001 | else | ||
1002 | stack = (unsigned long *)&stack; | ||
1003 | } | ||
1004 | endstack = (unsigned long *)(((unsigned long)stack + THREAD_SIZE - 1) & -THREAD_SIZE); | ||
1005 | |||
1006 | printk("Stack from %08lx:", (unsigned long)stack); | ||
1007 | for (i = 0; i < kstack_depth_to_print; i++) { | ||
1008 | if (stack + 1 > endstack) | ||
1009 | break; | ||
1010 | if (i % 8 == 0) | ||
1011 | printk("\n "); | ||
1012 | printk(" %08lx", *stack++); | ||
1013 | } | ||
1014 | printk("\n"); | ||
1015 | show_trace(stack); | ||
1016 | } | ||
1017 | |||
1018 | /* | ||
1019 | * The architecture-independent backtrace generator | ||
1020 | */ | ||
1021 | void dump_stack(void) | ||
1022 | { | ||
1023 | unsigned long stack; | ||
1024 | |||
1025 | show_trace(&stack); | ||
1026 | } | ||
1027 | |||
1028 | EXPORT_SYMBOL(dump_stack); | ||
1029 | |||
1030 | void bad_super_trap (struct frame *fp) | ||
1031 | { | ||
1032 | console_verbose(); | ||
1033 | if (fp->ptregs.vector < 4*sizeof(vec_names)/sizeof(vec_names[0])) | ||
1034 | printk ("*** %s *** FORMAT=%X\n", | ||
1035 | vec_names[(fp->ptregs.vector) >> 2], | ||
1036 | fp->ptregs.format); | ||
1037 | else | ||
1038 | printk ("*** Exception %d *** FORMAT=%X\n", | ||
1039 | (fp->ptregs.vector) >> 2, | ||
1040 | fp->ptregs.format); | ||
1041 | if (fp->ptregs.vector >> 2 == VEC_ADDRERR && CPU_IS_020_OR_030) { | ||
1042 | unsigned short ssw = fp->un.fmtb.ssw; | ||
1043 | |||
1044 | printk ("SSW=%#06x ", ssw); | ||
1045 | |||
1046 | if (ssw & RC) | ||
1047 | printk ("Pipe stage C instruction fault at %#010lx\n", | ||
1048 | (fp->ptregs.format) == 0xA ? | ||
1049 | fp->ptregs.pc + 2 : fp->un.fmtb.baddr - 2); | ||
1050 | if (ssw & RB) | ||
1051 | printk ("Pipe stage B instruction fault at %#010lx\n", | ||
1052 | (fp->ptregs.format) == 0xA ? | ||
1053 | fp->ptregs.pc + 4 : fp->un.fmtb.baddr); | ||
1054 | if (ssw & DF) | ||
1055 | printk ("Data %s fault at %#010lx in %s (pc=%#lx)\n", | ||
1056 | ssw & RW ? "read" : "write", | ||
1057 | fp->un.fmtb.daddr, space_names[ssw & DFC], | ||
1058 | fp->ptregs.pc); | ||
1059 | } | ||
1060 | printk ("Current process id is %d\n", current->pid); | ||
1061 | die_if_kernel("BAD KERNEL TRAP", &fp->ptregs, 0); | ||
1062 | } | ||
1063 | |||
1064 | asmlinkage void trap_c(struct frame *fp) | ||
1065 | { | ||
1066 | int sig; | ||
1067 | siginfo_t info; | ||
1068 | |||
1069 | if (fp->ptregs.sr & PS_S) { | ||
1070 | if ((fp->ptregs.vector >> 2) == VEC_TRACE) { | ||
1071 | /* traced a trapping instruction */ | ||
1072 | current->ptrace |= PT_DTRACE; | ||
1073 | } else | ||
1074 | bad_super_trap(fp); | ||
1075 | return; | ||
1076 | } | ||
1077 | |||
1078 | /* send the appropriate signal to the user program */ | ||
1079 | switch ((fp->ptregs.vector) >> 2) { | ||
1080 | case VEC_ADDRERR: | ||
1081 | info.si_code = BUS_ADRALN; | ||
1082 | sig = SIGBUS; | ||
1083 | break; | ||
1084 | case VEC_ILLEGAL: | ||
1085 | case VEC_LINE10: | ||
1086 | case VEC_LINE11: | ||
1087 | info.si_code = ILL_ILLOPC; | ||
1088 | sig = SIGILL; | ||
1089 | break; | ||
1090 | case VEC_PRIV: | ||
1091 | info.si_code = ILL_PRVOPC; | ||
1092 | sig = SIGILL; | ||
1093 | break; | ||
1094 | case VEC_COPROC: | ||
1095 | info.si_code = ILL_COPROC; | ||
1096 | sig = SIGILL; | ||
1097 | break; | ||
1098 | case VEC_TRAP1: | ||
1099 | case VEC_TRAP2: | ||
1100 | case VEC_TRAP3: | ||
1101 | case VEC_TRAP4: | ||
1102 | case VEC_TRAP5: | ||
1103 | case VEC_TRAP6: | ||
1104 | case VEC_TRAP7: | ||
1105 | case VEC_TRAP8: | ||
1106 | case VEC_TRAP9: | ||
1107 | case VEC_TRAP10: | ||
1108 | case VEC_TRAP11: | ||
1109 | case VEC_TRAP12: | ||
1110 | case VEC_TRAP13: | ||
1111 | case VEC_TRAP14: | ||
1112 | info.si_code = ILL_ILLTRP; | ||
1113 | sig = SIGILL; | ||
1114 | break; | ||
1115 | case VEC_FPBRUC: | ||
1116 | case VEC_FPOE: | ||
1117 | case VEC_FPNAN: | ||
1118 | info.si_code = FPE_FLTINV; | ||
1119 | sig = SIGFPE; | ||
1120 | break; | ||
1121 | case VEC_FPIR: | ||
1122 | info.si_code = FPE_FLTRES; | ||
1123 | sig = SIGFPE; | ||
1124 | break; | ||
1125 | case VEC_FPDIVZ: | ||
1126 | info.si_code = FPE_FLTDIV; | ||
1127 | sig = SIGFPE; | ||
1128 | break; | ||
1129 | case VEC_FPUNDER: | ||
1130 | info.si_code = FPE_FLTUND; | ||
1131 | sig = SIGFPE; | ||
1132 | break; | ||
1133 | case VEC_FPOVER: | ||
1134 | info.si_code = FPE_FLTOVF; | ||
1135 | sig = SIGFPE; | ||
1136 | break; | ||
1137 | case VEC_ZERODIV: | ||
1138 | info.si_code = FPE_INTDIV; | ||
1139 | sig = SIGFPE; | ||
1140 | break; | ||
1141 | case VEC_CHK: | ||
1142 | case VEC_TRAP: | ||
1143 | info.si_code = FPE_INTOVF; | ||
1144 | sig = SIGFPE; | ||
1145 | break; | ||
1146 | case VEC_TRACE: /* ptrace single step */ | ||
1147 | info.si_code = TRAP_TRACE; | ||
1148 | sig = SIGTRAP; | ||
1149 | break; | ||
1150 | case VEC_TRAP15: /* breakpoint */ | ||
1151 | info.si_code = TRAP_BRKPT; | ||
1152 | sig = SIGTRAP; | ||
1153 | break; | ||
1154 | default: | ||
1155 | info.si_code = ILL_ILLOPC; | ||
1156 | sig = SIGILL; | ||
1157 | break; | ||
1158 | } | ||
1159 | info.si_signo = sig; | ||
1160 | info.si_errno = 0; | ||
1161 | switch (fp->ptregs.format) { | ||
1162 | default: | ||
1163 | info.si_addr = (void *) fp->ptregs.pc; | ||
1164 | break; | ||
1165 | case 2: | ||
1166 | info.si_addr = (void *) fp->un.fmt2.iaddr; | ||
1167 | break; | ||
1168 | case 7: | ||
1169 | info.si_addr = (void *) fp->un.fmt7.effaddr; | ||
1170 | break; | ||
1171 | case 9: | ||
1172 | info.si_addr = (void *) fp->un.fmt9.iaddr; | ||
1173 | break; | ||
1174 | case 10: | ||
1175 | info.si_addr = (void *) fp->un.fmta.daddr; | ||
1176 | break; | ||
1177 | case 11: | ||
1178 | info.si_addr = (void *) fp->un.fmtb.daddr; | ||
1179 | break; | ||
1180 | } | ||
1181 | force_sig_info (sig, &info, current); | ||
1182 | } | ||
1183 | |||
1184 | void die_if_kernel (char *str, struct pt_regs *fp, int nr) | ||
1185 | { | ||
1186 | if (!(fp->sr & PS_S)) | ||
1187 | return; | ||
1188 | |||
1189 | console_verbose(); | ||
1190 | printk("%s: %08x\n",str,nr); | ||
1191 | print_modules(); | ||
1192 | printk("PC: [<%08lx>]",fp->pc); | ||
1193 | print_symbol(" %s\n", fp->pc); | ||
1194 | printk("\nSR: %04x SP: %p a2: %08lx\n", | ||
1195 | fp->sr, fp, fp->a2); | ||
1196 | printk("d0: %08lx d1: %08lx d2: %08lx d3: %08lx\n", | ||
1197 | fp->d0, fp->d1, fp->d2, fp->d3); | ||
1198 | printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", | ||
1199 | fp->d4, fp->d5, fp->a0, fp->a1); | ||
1200 | |||
1201 | printk("Process %s (pid: %d, stackpage=%08lx)\n", | ||
1202 | current->comm, current->pid, PAGE_SIZE+(unsigned long)current); | ||
1203 | show_stack(NULL, (unsigned long *)fp); | ||
1204 | do_exit(SIGSEGV); | ||
1205 | } | ||
1206 | |||
1207 | /* | ||
1208 | * This function is called if an error occur while accessing | ||
1209 | * user-space from the fpsp040 code. | ||
1210 | */ | ||
1211 | asmlinkage void fpsp040_die(void) | ||
1212 | { | ||
1213 | do_exit(SIGSEGV); | ||
1214 | } | ||
1215 | |||
1216 | #ifdef CONFIG_M68KFPU_EMU | ||
1217 | asmlinkage void fpemu_signal(int signal, int code, void *addr) | ||
1218 | { | ||
1219 | siginfo_t info; | ||
1220 | |||
1221 | info.si_signo = signal; | ||
1222 | info.si_errno = 0; | ||
1223 | info.si_code = code; | ||
1224 | info.si_addr = addr; | ||
1225 | force_sig_info(signal, &info, current); | ||
1226 | } | ||
1227 | #endif | ||