OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [arch/] [m68k/] [kernel/] [traps.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.