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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [arch/] [alpha/] [kernel/] [traps.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1622 jcastillo
/*
2
 * kernel/traps.c
3
 *
4
 * (C) Copyright 1994 Linus Torvalds
5
 */
6
 
7
/*
8
 * This file initializes the trap entry points
9
 */
10
 
11
#include <linux/config.h>
12
#include <linux/mm.h>
13
#include <linux/sched.h>
14
#include <linux/tty.h>
15
 
16
#include <asm/gentrap.h>
17
#include <asm/segment.h>
18
#include <asm/unaligned.h>
19
 
20
void die_if_kernel(char * str, struct pt_regs * regs, long err)
21
{
22
        long i;
23
        unsigned long sp;
24
        unsigned int * pc;
25
 
26
        if (regs->ps & 8)
27
                return;
28
        printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
29
        sp = (unsigned long) (regs+1);
30
        printk("pc = [<%lx>] ps = %04lx\n", regs->pc, regs->ps);
31
        printk("rp = [<%lx>] sp = %lx\n", regs->r26, sp);
32
        printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
33
                regs->r0, regs->r1, regs->r2, regs->r3);
34
        printk("r8=%lx\n", regs->r8);
35
        printk("r16=%lx r17=%lx r18=%lx r19=%lx\n",
36
                regs->r16, regs->r17, regs->r18, regs->r19);
37
        printk("r20=%lx r21=%lx r22=%lx r23=%lx\n",
38
                regs->r20, regs->r21, regs->r22, regs->r23);
39
        printk("r24=%lx r25=%lx r26=%lx r27=%lx\n",
40
                regs->r24, regs->r25, regs->r26, regs->r27);
41
        printk("r28=%lx r29=%lx r30=%lx\n",
42
                regs->r28, regs->gp, sp);
43
        printk("Code:");
44
        pc = (unsigned int *) regs->pc;
45
        for (i = -3; i < 6; i++)
46
                printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
47
        printk("\n");
48
        do_exit(SIGSEGV);
49
}
50
 
51
asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
52
                            unsigned long a2, unsigned long a3,
53
                            unsigned long a4, unsigned long a5,
54
                            struct pt_regs regs)
55
{
56
        if ((summary & 1)) {
57
                extern long alpha_fp_emul_imprecise (struct pt_regs * regs,
58
                                                     unsigned long write_mask);
59
                /*
60
                 * Software-completion summary bit is set, so try to
61
                 * emulate the instruction.
62
                 */
63
                if (alpha_fp_emul_imprecise(&regs, write_mask)) {
64
                        return;         /* emulation was successful */
65
                }
66
        }
67
        printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
68
                current->comm, regs.pc, summary, write_mask);
69
        die_if_kernel("Arithmetic fault", &regs, 0);
70
        force_sig(SIGFPE, current);
71
}
72
 
73
asmlinkage void do_entIF(unsigned long type, unsigned long a1,
74
                         unsigned long a2, unsigned long a3, unsigned long a4,
75
                         unsigned long a5, struct pt_regs regs)
76
{
77
        extern int ptrace_cancel_bpt (struct task_struct *who);
78
 
79
        die_if_kernel("Instruction fault", &regs, type);
80
        switch (type) {
81
              case 0: /* breakpoint */
82
                if (ptrace_cancel_bpt(current)) {
83
                        regs.pc -= 4;   /* make pc point to former bpt */
84
                }
85
                force_sig(SIGTRAP, current);
86
                break;
87
 
88
              case 2: /* gentrap */
89
                /*
90
                 * The exception code should be passed on to the signal
91
                 * handler as the second argument.  Linux doesn't do that
92
                 * yet (also notice that Linux *always* behaves like
93
                 * DEC Unix with SA_SIGINFO off; see DEC Unix man page
94
                 * for sigaction(2)).
95
                 */
96
                switch ((long) regs.r16) {
97
                      case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
98
                      case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
99
                      case GEN_FLTINE:
100
                        force_sig(SIGFPE, current);
101
                        break;
102
 
103
                      case GEN_DECOVF:
104
                      case GEN_DECDIV:
105
                      case GEN_DECINV:
106
                      case GEN_ROPRAND:
107
                      case GEN_ASSERTERR:
108
                      case GEN_NULPTRERR:
109
                      case GEN_STKOVF:
110
                      case GEN_STRLENERR:
111
                      case GEN_SUBSTRERR:
112
                      case GEN_RANGERR:
113
                      case GEN_SUBRNG:
114
                      case GEN_SUBRNG1:
115
                      case GEN_SUBRNG2:
116
                      case GEN_SUBRNG3:
117
                      case GEN_SUBRNG4:
118
                      case GEN_SUBRNG5:
119
                      case GEN_SUBRNG6:
120
                      case GEN_SUBRNG7:
121
                        force_sig(SIGILL, current);
122
                        break;
123
                }
124
                break;
125
 
126
              case 1: /* bugcheck */
127
              case 3: /* FEN fault */
128
                force_sig(SIGILL, current);
129
                break;
130
 
131
              case 4: /* opDEC */
132
#ifdef CONFIG_ALPHA_NEED_ROUNDING_EMULATION
133
                {
134
                        extern long alpha_fp_emul (unsigned long pc);
135
                        unsigned int opcode;
136
 
137
                        /* get opcode of faulting instruction: */
138
                        opcode = get_user((__u32*)(regs.pc - 4)) >> 26;
139
                        if (opcode == 0x16) {
140
                                /*
141
                                 * It's a FLTI instruction, emulate it
142
                                 * (we don't do no stinkin' VAX fp...)
143
                                 */
144
                                if (!alpha_fp_emul(regs.pc - 4))
145
                                        force_sig(SIGFPE, current);
146
                                break;
147
                        }
148
                }
149
#endif
150
                force_sig(SIGILL, current);
151
                break;
152
 
153
              default:
154
                panic("do_entIF: unexpected instruction-fault type");
155
        }
156
}
157
 
158
/*
159
 * entUna has a different register layout to be reasonably simple. It
160
 * needs access to all the integer registers (the kernel doesn't use
161
 * fp-regs), and it needs to have them in order for simpler access.
162
 *
163
 * Due to the non-standard register layout (and because we don't want
164
 * to handle floating-point regs), user-mode unaligned accesses are
165
 * handled separately by do_entUnaUser below.
166
 *
167
 * Oh, btw, we don't handle the "gp" register correctly, but if we fault
168
 * on a gp-register unaligned load/store, something is _very_ wrong
169
 * in the kernel anyway..
170
 */
171
struct allregs {
172
        unsigned long regs[32];
173
        unsigned long ps, pc, gp, a0, a1, a2;
174
};
175
 
176
struct unaligned_stat {
177
        unsigned long count, va, pc;
178
} unaligned[2];
179
 
180
asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
181
        unsigned long a3, unsigned long a4, unsigned long a5,
182
        struct allregs regs)
183
{
184
        static int cnt = 0;
185
        static long last_time = 0;
186
 
187
        if (cnt >= 5 && jiffies - last_time > 5*HZ) {
188
                cnt = 0;
189
        }
190
        if (++cnt < 5) {
191
                printk("kernel: unaligned trap at %016lx: %p %lx %ld\n",
192
                       regs.pc - 4, va, opcode, reg);
193
        }
194
        last_time = jiffies;
195
 
196
        ++unaligned[0].count;
197
        unaligned[0].va = (unsigned long) va - 4;
198
        unaligned[0].pc = regs.pc;
199
 
200
        /* $16-$18 are PAL-saved, and are offset by 19 entries */
201
        if (reg >= 16 && reg <= 18)
202
                reg += 19;
203
        switch (opcode) {
204
              case 0x28: /* ldl */
205
                *(reg+regs.regs) = get_unaligned((int *)va);
206
                return;
207
              case 0x29: /* ldq */
208
                *(reg+regs.regs) = get_unaligned((long *)va);
209
                return;
210
              case 0x2c: /* stl */
211
                put_unaligned(*(reg+regs.regs), (int *)va);
212
                return;
213
              case 0x2d: /* stq */
214
                put_unaligned(*(reg+regs.regs), (long *)va);
215
                return;
216
        }
217
        printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
218
                regs.pc, va, opcode, reg);
219
        do_exit(SIGSEGV);
220
}
221
 
222
/*
223
 * Convert an s-floating point value in memory format to the
224
 * corresponding value in register format.  The exponent
225
 * needs to be remapped to preserve non-finite values
226
 * (infinities, not-a-numbers, denormals).
227
 */
228
static inline unsigned long s_mem_to_reg (unsigned long s_mem)
229
{
230
        unsigned long frac    = (s_mem >>  0) & 0x7fffff;
231
        unsigned long sign    = (s_mem >> 31) & 0x1;
232
        unsigned long exp_msb = (s_mem >> 30) & 0x1;
233
        unsigned long exp_low = (s_mem >> 23) & 0x7f;
234
        unsigned long exp;
235
 
236
        exp = (exp_msb << 10) | exp_low;        /* common case */
237
        if (exp_msb) {
238
                if (exp_low == 0x7f) {
239
                        exp = 0x7ff;
240
                }
241
        } else {
242
                if (exp_low == 0x00) {
243
                        exp = 0x000;
244
                } else {
245
                        exp |= (0x7 << 7);
246
                }
247
        }
248
        return (sign << 63) | (exp << 52) | (frac << 29);
249
}
250
 
251
/*
252
 * Convert an s-floating point value in register format to the
253
 * corresponding value in memory format.
254
 */
255
static inline unsigned long s_reg_to_mem (unsigned long s_reg)
256
{
257
        return ((s_reg >> 62) << 30) | ((s_reg << 5) >> 34);
258
}
259
 
260
/*
261
 * Handle user-level unaligned fault.  Handling user-level unaligned
262
 * faults is *extremely* slow and produces nasty messages.  A user
263
 * program *should* fix unaligned faults ASAP.
264
 *
265
 * Notice that we have (almost) the regular kernel stack layout here,
266
 * so finding the appropriate registers is a little more difficult
267
 * than in the kernel case.
268
 *
269
 * Finally, we handle regular integer load/stores only.  In
270
 * particular, load-linked/store-conditionally and floating point
271
 * load/stores are not supported.  The former make no sense with
272
 * unaligned faults (they are guaranteed to fail) and I don't think
273
 * the latter will occur in any decent program.
274
 *
275
 * Sigh. We *do* have to handle some FP operations, because GCC will
276
 * uses them as temporary storage for integer memory to memory copies.
277
 * However, we need to deal with stt/ldt and sts/lds only.
278
 */
279
asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg,
280
                              unsigned long * frame)
281
{
282
        long dir, size;
283
        unsigned long *reg_addr, *pc_addr, usp, zero = 0;
284
        static int cnt = 0;
285
        static long last_time = 0;
286
        extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
287
        extern unsigned long alpha_read_fp_reg (unsigned long reg);
288
 
289
        pc_addr = frame + 7 + 20 + 3 /* em86 */ + 1;    /* pc in PAL frame */
290
 
291
        if (cnt >= 5 && jiffies - last_time > 5*HZ) {
292
                cnt = 0;
293
        }
294
        if (++cnt < 5) {
295
                printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
296
                       current->comm, current->pid,
297
                       *pc_addr - 4, va, opcode, reg);
298
        }
299
        last_time = jiffies;
300
 
301
        ++unaligned[1].count;
302
        unaligned[1].va = (unsigned long) va - 4;
303
        unaligned[1].pc = *pc_addr;
304
 
305
        dir = VERIFY_READ;
306
        if (opcode & 0x4) {
307
                /* it's a stl, stq, stt, or sts */
308
                dir = VERIFY_WRITE;
309
        }
310
        size = 4;
311
        if (opcode & 0x1) {
312
                /* it's a quadword op */
313
                size = 8;
314
        }
315
        if (verify_area(dir, va, size)) {
316
                *pc_addr -= 4;  /* make pc point to faulting insn */
317
                force_sig(SIGSEGV, current);
318
                return;
319
        }
320
 
321
        reg_addr = frame;
322
        if (opcode >= 0x28) {
323
                /* it's an integer load/store */
324
                switch (reg) {
325
                      case 0: case 1: case 2: case 3: case 4:
326
                      case 5: case 6: case 7: case 8:
327
                        /* v0-t7 in SAVE_ALL frame */
328
                        reg_addr += 7 + reg;
329
                        break;
330
 
331
                      case 9: case 10: case 11: case 12:
332
                      case 13: case 14: case 15:
333
                        /* s0-s6 in entUna frame */
334
                        reg_addr += (reg - 9);
335
                        break;
336
 
337
                      case 16: case 17: case 18:
338
                        /* a0-a2 in PAL frame */
339
                        reg_addr += 7 + 20 + 3 /* em86 */ + 3 + (reg - 16);
340
                        break;
341
 
342
                      case 19: case 20: case 21: case 22: case 23:
343
                      case 24: case 25: case 26: case 27: case 28:
344
                        /* a3-at in SAVE_ALL frame */
345
                        reg_addr += 7 + 9 + (reg - 19);
346
                        break;
347
 
348
                      case 29:
349
                        /* gp in PAL frame */
350
                        reg_addr += 7 + 20 + 3 /* em86 */ + 2;
351
                        break;
352
 
353
                      case 30:
354
                        /* usp in PAL regs */
355
                        usp = rdusp();
356
                        reg_addr = &usp;
357
                        break;
358
 
359
                      case 31:
360
                        /* zero "register" */
361
                        reg_addr = &zero;
362
                        break;
363
                }
364
        }
365
 
366
        switch (opcode) {
367
              case 0x22: /* lds */
368
                alpha_write_fp_reg(reg, s_mem_to_reg(
369
                        get_unaligned((unsigned int *)va)));
370
                break;
371
              case 0x26: /* sts */
372
                put_unaligned(s_reg_to_mem(alpha_read_fp_reg(reg)),
373
                              (unsigned int *)va);
374
                break;
375
 
376
              case 0x23: /* ldt */
377
                alpha_write_fp_reg(reg, get_unaligned((unsigned long *)va));
378
                break;
379
              case 0x27: /* stt */
380
                put_unaligned(alpha_read_fp_reg(reg), (unsigned long *)va);
381
                break;
382
 
383
              case 0x28: /* ldl */
384
                *reg_addr = get_unaligned((int *)va);
385
                break;
386
              case 0x2c: /* stl */
387
                put_unaligned(*reg_addr, (int *)va);
388
                break;
389
 
390
              case 0x29: /* ldq */
391
                *reg_addr = get_unaligned((long *)va);
392
                break;
393
              case 0x2d: /* stq */
394
                put_unaligned(*reg_addr, (long *)va);
395
                break;
396
 
397
              default:
398
                *pc_addr -= 4;  /* make pc point to faulting insn */
399
                force_sig(SIGBUS, current);
400
                return;
401
        }
402
 
403
        if (opcode >= 0x28 && reg == 30 && dir == VERIFY_WRITE) {
404
                wrusp(usp);
405
        }
406
}
407
 
408
/*
409
 * DEC means people to use the "retsys" instruction for return from
410
 * a system call, but they are clearly misguided about this. We use
411
 * "rti" in all cases, and fill in the stack with the return values.
412
 * That should make signal handling etc much cleaner.
413
 *
414
 * Even more horribly, DEC doesn't allow system calls from kernel mode.
415
 * "Security" features letting the user do something the kernel can't
416
 * are a thinko. DEC palcode is strange. The PAL-code designers probably
417
 * got terminally tainted by VMS at some point.
418
 */
419
asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
420
                          unsigned long a3, unsigned long a4, unsigned long a5,
421
                          struct pt_regs regs)
422
{
423
        if (regs.r0 != 112 && regs.r0 < 300)
424
                printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
425
        return -ENOSYS;
426
}
427
 
428
extern asmlinkage void entMM(void);
429
extern asmlinkage void entIF(void);
430
extern asmlinkage void entArith(void);
431
extern asmlinkage void entUna(void);
432
extern asmlinkage void entSys(void);
433
 
434
void trap_init(void)
435
{
436
        unsigned long gptr;
437
 
438
        /*
439
         * Tell PAL-code what global pointer we want in the kernel..
440
         */
441
        __asm__("br %0,___tmp\n"
442
                "___tmp:\tldgp %0,0(%0)"
443
                : "=r" (gptr));
444
        wrkgp(gptr);
445
 
446
        wrent(entArith, 1);
447
        wrent(entMM, 2);
448
        wrent(entIF, 3);
449
        wrent(entUna, 4);
450
        wrent(entSys, 5);
451
}

powered by: WebSVN 2.1.0

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