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

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [sparc/] [kernel/] [traps.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/* $Id: traps.c,v 1.64 2000/09/03 15:00:49 anton Exp $
2
 * arch/sparc/kernel/traps.c
3
 *
4
 * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
5
 * Copyright 2000 Jakub Jelinek (jakub@redhat.com)
6
 */
7
 
8
/*
9
 * I hate traps on the sparc, grrr...
10
 */
11
 
12
#include <linux/sched.h>  /* for jiffies */
13
#include <linux/kernel.h>
14
#include <linux/kallsyms.h>
15
#include <linux/signal.h>
16
#include <linux/smp.h>
17
#include <linux/smp_lock.h>
18
#include <linux/kdebug.h>
19
 
20
#include <asm/delay.h>
21
#include <asm/system.h>
22
#include <asm/ptrace.h>
23
#include <asm/oplib.h>
24
#include <asm/page.h>
25
#include <asm/pgtable.h>
26
#include <asm/unistd.h>
27
#include <asm/traps.h>
28
 
29
/* #define TRAP_DEBUG */
30
 
31
struct trap_trace_entry {
32
        unsigned long pc;
33
        unsigned long type;
34
};
35
 
36
int trap_curbuf = 0;
37
struct trap_trace_entry trapbuf[1024];
38
 
39
void syscall_trace_entry(struct pt_regs *regs)
40
{
41
        printk("%s[%d]: ", current->comm, task_pid_nr(current));
42
        printk("scall<%d> (could be %d)\n", (int) regs->u_regs[UREG_G1],
43
               (int) regs->u_regs[UREG_I0]);
44
}
45
 
46
void syscall_trace_exit(struct pt_regs *regs)
47
{
48
}
49
 
50
void sun4m_nmi(struct pt_regs *regs)
51
{
52
        unsigned long afsr, afar;
53
 
54
        printk("Aieee: sun4m NMI received!\n");
55
        /* XXX HyperSparc hack XXX */
56
        __asm__ __volatile__("mov 0x500, %%g1\n\t"
57
                             "lda [%%g1] 0x4, %0\n\t"
58
                             "mov 0x600, %%g1\n\t"
59
                             "lda [%%g1] 0x4, %1\n\t" :
60
                             "=r" (afsr), "=r" (afar));
61
        printk("afsr=%08lx afar=%08lx\n", afsr, afar);
62
        printk("you lose buddy boy...\n");
63
        show_regs(regs);
64
        prom_halt();
65
}
66
 
67
void sun4d_nmi(struct pt_regs *regs)
68
{
69
        printk("Aieee: sun4d NMI received!\n");
70
        printk("you lose buddy boy...\n");
71
        show_regs(regs);
72
        prom_halt();
73
}
74
 
75
void instruction_dump (unsigned long *pc)
76
{
77
        int i;
78
 
79
        if((((unsigned long) pc) & 3))
80
                return;
81
 
82
        for(i = -3; i < 6; i++)
83
                printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
84
        printk("\n");
85
}
86
 
87
#define __SAVE __asm__ __volatile__("save %sp, -0x40, %sp\n\t")
88
#define __RESTORE __asm__ __volatile__("restore %g0, %g0, %g0\n\t")
89
 
90
void die_if_kernel(char *str, struct pt_regs *regs)
91
{
92
        static int die_counter;
93
        int count = 0;
94
 
95
        /* Amuse the user. */
96
        printk(
97
"              \\|/ ____ \\|/\n"
98
"              \"@'/ ,. \\`@\"\n"
99
"              /_| \\__/ |_\\\n"
100
"                 \\__U_/\n");
101
 
102
        printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter);
103
        show_regs(regs);
104
        add_taint(TAINT_DIE);
105
 
106
        __SAVE; __SAVE; __SAVE; __SAVE;
107
        __SAVE; __SAVE; __SAVE; __SAVE;
108
        __RESTORE; __RESTORE; __RESTORE; __RESTORE;
109
        __RESTORE; __RESTORE; __RESTORE; __RESTORE;
110
 
111
        {
112
                struct reg_window *rw = (struct reg_window *)regs->u_regs[UREG_FP];
113
 
114
                /* Stop the back trace when we hit userland or we
115
                 * find some badly aligned kernel stack. Set an upper
116
                 * bound in case our stack is trashed and we loop.
117
                 */
118
                while(rw                                        &&
119
                      count++ < 30                              &&
120
                      (((unsigned long) rw) >= PAGE_OFFSET)     &&
121
                      !(((unsigned long) rw) & 0x7)) {
122
                        printk("Caller[%08lx]", rw->ins[7]);
123
                        print_symbol(": %s\n", rw->ins[7]);
124
                        rw = (struct reg_window *)rw->ins[6];
125
                }
126
        }
127
        printk("Instruction DUMP:");
128
        instruction_dump ((unsigned long *) regs->pc);
129
        if(regs->psr & PSR_PS)
130
                do_exit(SIGKILL);
131
        do_exit(SIGSEGV);
132
}
133
 
134
void do_hw_interrupt(struct pt_regs *regs, unsigned long type)
135
{
136
        siginfo_t info;
137
 
138
        if(type < 0x80) {
139
                /* Sun OS's puke from bad traps, Linux survives! */
140
                printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
141
                die_if_kernel("Whee... Hello Mr. Penguin", regs);
142
        }
143
 
144
        if(regs->psr & PSR_PS)
145
                die_if_kernel("Kernel bad trap", regs);
146
 
147
        info.si_signo = SIGILL;
148
        info.si_errno = 0;
149
        info.si_code = ILL_ILLTRP;
150
        info.si_addr = (void __user *)regs->pc;
151
        info.si_trapno = type - 0x80;
152
        force_sig_info(SIGILL, &info, current);
153
}
154
 
155
void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
156
                            unsigned long psr)
157
{
158
        extern int do_user_muldiv (struct pt_regs *, unsigned long);
159
        siginfo_t info;
160
 
161
        if(psr & PSR_PS)
162
                die_if_kernel("Kernel illegal instruction", regs);
163
#ifdef TRAP_DEBUG
164
        printk("Ill instr. at pc=%08lx instruction is %08lx\n",
165
               regs->pc, *(unsigned long *)regs->pc);
166
#endif
167
        if (!do_user_muldiv (regs, pc))
168
                return;
169
 
170
        info.si_signo = SIGILL;
171
        info.si_errno = 0;
172
        info.si_code = ILL_ILLOPC;
173
        info.si_addr = (void __user *)pc;
174
        info.si_trapno = 0;
175
        send_sig_info(SIGILL, &info, current);
176
}
177
 
178
void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
179
                         unsigned long psr)
180
{
181
        siginfo_t info;
182
 
183
        if(psr & PSR_PS)
184
                die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
185
        info.si_signo = SIGILL;
186
        info.si_errno = 0;
187
        info.si_code = ILL_PRVOPC;
188
        info.si_addr = (void __user *)pc;
189
        info.si_trapno = 0;
190
        send_sig_info(SIGILL, &info, current);
191
}
192
 
193
/* XXX User may want to be allowed to do this. XXX */
194
 
195
void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
196
                            unsigned long psr)
197
{
198
        siginfo_t info;
199
 
200
        if(regs->psr & PSR_PS) {
201
                printk("KERNEL MNA at pc %08lx npc %08lx called by %08lx\n", pc, npc,
202
                       regs->u_regs[UREG_RETPC]);
203
                die_if_kernel("BOGUS", regs);
204
                /* die_if_kernel("Kernel MNA access", regs); */
205
        }
206
#if 0
207
        show_regs (regs);
208
        instruction_dump ((unsigned long *) regs->pc);
209
        printk ("do_MNA!\n");
210
#endif
211
        info.si_signo = SIGBUS;
212
        info.si_errno = 0;
213
        info.si_code = BUS_ADRALN;
214
        info.si_addr = /* FIXME: Should dig out mna address */ (void *)0;
215
        info.si_trapno = 0;
216
        send_sig_info(SIGBUS, &info, current);
217
}
218
 
219
extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
220
                   void *fpqueue, unsigned long *fpqdepth);
221
extern void fpload(unsigned long *fpregs, unsigned long *fsr);
222
 
223
static unsigned long init_fsr = 0x0UL;
224
static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
225
                { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
226
                  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
227
                  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
228
                  ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
229
 
230
void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
231
                 unsigned long psr)
232
{
233
        /* Sanity check... */
234
        if(psr & PSR_PS)
235
                die_if_kernel("Kernel gets FloatingPenguinUnit disabled trap", regs);
236
 
237
        put_psr(get_psr() | PSR_EF);    /* Allow FPU ops. */
238
        regs->psr |= PSR_EF;
239
#ifndef CONFIG_SMP
240
        if(last_task_used_math == current)
241
                return;
242
        if(last_task_used_math) {
243
                /* Other processes fpu state, save away */
244
                struct task_struct *fptask = last_task_used_math;
245
                fpsave(&fptask->thread.float_regs[0], &fptask->thread.fsr,
246
                       &fptask->thread.fpqueue[0], &fptask->thread.fpqdepth);
247
        }
248
        last_task_used_math = current;
249
        if(used_math()) {
250
                fpload(&current->thread.float_regs[0], &current->thread.fsr);
251
        } else {
252
                /* Set initial sane state. */
253
                fpload(&init_fregs[0], &init_fsr);
254
                set_used_math();
255
        }
256
#else
257
        if(!used_math()) {
258
                fpload(&init_fregs[0], &init_fsr);
259
                set_used_math();
260
        } else {
261
                fpload(&current->thread.float_regs[0], &current->thread.fsr);
262
        }
263
        set_thread_flag(TIF_USEDFPU);
264
#endif
265
}
266
 
267
static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
268
static unsigned long fake_fsr;
269
static unsigned long fake_queue[32] __attribute__ ((aligned (8)));
270
static unsigned long fake_depth;
271
 
272
extern int do_mathemu(struct pt_regs *, struct task_struct *);
273
 
274
void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
275
                 unsigned long psr)
276
{
277
        static int calls;
278
        siginfo_t info;
279
        unsigned long fsr;
280
        int ret = 0;
281
#ifndef CONFIG_SMP
282
        struct task_struct *fpt = last_task_used_math;
283
#else
284
        struct task_struct *fpt = current;
285
#endif
286
        put_psr(get_psr() | PSR_EF);
287
        /* If nobody owns the fpu right now, just clear the
288
         * error into our fake static buffer and hope it don't
289
         * happen again.  Thank you crashme...
290
         */
291
#ifndef CONFIG_SMP
292
        if(!fpt) {
293
#else
294
        if (!test_tsk_thread_flag(fpt, TIF_USEDFPU)) {
295
#endif
296
                fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
297
                regs->psr &= ~PSR_EF;
298
                return;
299
        }
300
        fpsave(&fpt->thread.float_regs[0], &fpt->thread.fsr,
301
               &fpt->thread.fpqueue[0], &fpt->thread.fpqdepth);
302
#ifdef DEBUG_FPU
303
        printk("Hmm, FP exception, fsr was %016lx\n", fpt->thread.fsr);
304
#endif
305
 
306
        switch ((fpt->thread.fsr & 0x1c000)) {
307
        /* switch on the contents of the ftt [floating point trap type] field */
308
#ifdef DEBUG_FPU
309
        case (1 << 14):
310
                printk("IEEE_754_exception\n");
311
                break;
312
#endif
313
        case (2 << 14):  /* unfinished_FPop (underflow & co) */
314
        case (3 << 14):  /* unimplemented_FPop (quad stuff, maybe sqrt) */
315
                ret = do_mathemu(regs, fpt);
316
                break;
317
#ifdef DEBUG_FPU
318
        case (4 << 14):
319
                printk("sequence_error (OS bug...)\n");
320
                break;
321
        case (5 << 14):
322
                printk("hardware_error (uhoh!)\n");
323
                break;
324
        case (6 << 14):
325
                printk("invalid_fp_register (user error)\n");
326
                break;
327
#endif /* DEBUG_FPU */
328
        }
329
        /* If we successfully emulated the FPop, we pretend the trap never happened :-> */
330
        if (ret) {
331
                fpload(&current->thread.float_regs[0], &current->thread.fsr);
332
                return;
333
        }
334
        /* nope, better SIGFPE the offending process... */
335
 
336
#ifdef CONFIG_SMP
337
        clear_tsk_thread_flag(fpt, TIF_USEDFPU);
338
#endif
339
        if(psr & PSR_PS) {
340
                /* The first fsr store/load we tried trapped,
341
                 * the second one will not (we hope).
342
                 */
343
                printk("WARNING: FPU exception from kernel mode. at pc=%08lx\n",
344
                       regs->pc);
345
                regs->pc = regs->npc;
346
                regs->npc += 4;
347
                calls++;
348
                if(calls > 2)
349
                        die_if_kernel("Too many Penguin-FPU traps from kernel mode",
350
                                      regs);
351
                return;
352
        }
353
 
354
        fsr = fpt->thread.fsr;
355
        info.si_signo = SIGFPE;
356
        info.si_errno = 0;
357
        info.si_addr = (void __user *)pc;
358
        info.si_trapno = 0;
359
        info.si_code = __SI_FAULT;
360
        if ((fsr & 0x1c000) == (1 << 14)) {
361
                if (fsr & 0x10)
362
                        info.si_code = FPE_FLTINV;
363
                else if (fsr & 0x08)
364
                        info.si_code = FPE_FLTOVF;
365
                else if (fsr & 0x04)
366
                        info.si_code = FPE_FLTUND;
367
                else if (fsr & 0x02)
368
                        info.si_code = FPE_FLTDIV;
369
                else if (fsr & 0x01)
370
                        info.si_code = FPE_FLTRES;
371
        }
372
        send_sig_info(SIGFPE, &info, fpt);
373
#ifndef CONFIG_SMP
374
        last_task_used_math = NULL;
375
#endif
376
        regs->psr &= ~PSR_EF;
377
        if(calls > 0)
378
                calls=0;
379
}
380
 
381
void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
382
                         unsigned long psr)
383
{
384
        siginfo_t info;
385
 
386
        if(psr & PSR_PS)
387
                die_if_kernel("Penguin overflow trap from kernel mode", regs);
388
        info.si_signo = SIGEMT;
389
        info.si_errno = 0;
390
        info.si_code = EMT_TAGOVF;
391
        info.si_addr = (void __user *)pc;
392
        info.si_trapno = 0;
393
        send_sig_info(SIGEMT, &info, current);
394
}
395
 
396
void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
397
                       unsigned long psr)
398
{
399
#ifdef TRAP_DEBUG
400
        printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
401
               pc, npc, psr);
402
#endif
403
        if(psr & PSR_PS)
404
                panic("Tell me what a watchpoint trap is, and I'll then deal "
405
                      "with such a beast...");
406
}
407
 
408
void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
409
                       unsigned long psr)
410
{
411
        siginfo_t info;
412
 
413
#ifdef TRAP_DEBUG
414
        printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
415
               pc, npc, psr);
416
#endif
417
        info.si_signo = SIGBUS;
418
        info.si_errno = 0;
419
        info.si_code = BUS_OBJERR;
420
        info.si_addr = (void __user *)pc;
421
        info.si_trapno = 0;
422
        force_sig_info(SIGBUS, &info, current);
423
}
424
 
425
void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
426
                        unsigned long psr)
427
{
428
        siginfo_t info;
429
 
430
        info.si_signo = SIGILL;
431
        info.si_errno = 0;
432
        info.si_code = ILL_COPROC;
433
        info.si_addr = (void __user *)pc;
434
        info.si_trapno = 0;
435
        send_sig_info(SIGILL, &info, current);
436
}
437
 
438
void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
439
                         unsigned long psr)
440
{
441
        siginfo_t info;
442
 
443
#ifdef TRAP_DEBUG
444
        printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
445
               pc, npc, psr);
446
#endif
447
        info.si_signo = SIGILL;
448
        info.si_errno = 0;
449
        info.si_code = ILL_COPROC;
450
        info.si_addr = (void __user *)pc;
451
        info.si_trapno = 0;
452
        send_sig_info(SIGILL, &info, current);
453
}
454
 
455
void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
456
                       unsigned long psr)
457
{
458
        siginfo_t info;
459
 
460
        info.si_signo = SIGFPE;
461
        info.si_errno = 0;
462
        info.si_code = FPE_INTDIV;
463
        info.si_addr = (void __user *)pc;
464
        info.si_trapno = 0;
465
        send_sig_info(SIGFPE, &info, current);
466
}
467
 
468
#ifdef CONFIG_DEBUG_BUGVERBOSE
469
void do_BUG(const char *file, int line)
470
{
471
        // bust_spinlocks(1);   XXX Not in our original BUG()
472
        printk("kernel BUG at %s:%d!\n", file, line);
473
}
474
#endif
475
 
476
/* Since we have our mappings set up, on multiprocessors we can spin them
477
 * up here so that timer interrupts work during initialization.
478
 */
479
 
480
extern void sparc_cpu_startup(void);
481
 
482
int linux_smp_still_initting;
483
unsigned int thiscpus_tbr;
484
int thiscpus_mid;
485
 
486
void trap_init(void)
487
{
488
        extern void thread_info_offsets_are_bolixed_pete(void);
489
 
490
        /* Force linker to barf if mismatched */
491
        if (TI_UWINMASK    != offsetof(struct thread_info, uwinmask) ||
492
            TI_TASK        != offsetof(struct thread_info, task) ||
493
            TI_EXECDOMAIN  != offsetof(struct thread_info, exec_domain) ||
494
            TI_FLAGS       != offsetof(struct thread_info, flags) ||
495
            TI_CPU         != offsetof(struct thread_info, cpu) ||
496
            TI_PREEMPT     != offsetof(struct thread_info, preempt_count) ||
497
            TI_SOFTIRQ     != offsetof(struct thread_info, softirq_count) ||
498
            TI_HARDIRQ     != offsetof(struct thread_info, hardirq_count) ||
499
            TI_KSP         != offsetof(struct thread_info, ksp) ||
500
            TI_KPC         != offsetof(struct thread_info, kpc) ||
501
            TI_KPSR        != offsetof(struct thread_info, kpsr) ||
502
            TI_KWIM        != offsetof(struct thread_info, kwim) ||
503
            TI_REG_WINDOW  != offsetof(struct thread_info, reg_window) ||
504
            TI_RWIN_SPTRS  != offsetof(struct thread_info, rwbuf_stkptrs) ||
505
            TI_W_SAVED     != offsetof(struct thread_info, w_saved))
506
                thread_info_offsets_are_bolixed_pete();
507
 
508
        /* Attach to the address space of init_task. */
509
        atomic_inc(&init_mm.mm_count);
510
        current->active_mm = &init_mm;
511
 
512
        /* NOTE: Other cpus have this done as they are started
513
         *       up on SMP.
514
         */
515
}

powered by: WebSVN 2.1.0

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