root/arch/sparc/kernel/traps.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. syscall_trace_entry
  2. syscall_trace_exit
  3. sun4m_nmi
  4. die_if_kernel
  5. do_hw_interrupt
  6. do_illegal_instruction
  7. do_priv_instruction
  8. do_memaccess_unaligned
  9. do_fpd_trap
  10. do_fpe_trap
  11. handle_tag_overflow
  12. handle_watchpoint
  13. handle_reg_access
  14. handle_cp_disabled
  15. handle_bad_flush
  16. handle_cp_exception
  17. handle_hw_divzero
  18. trap_init

   1 /* $Id: traps.c,v 1.43 1996/04/24 09:09:42 davem Exp $
   2  * arch/sparc/kernel/traps.c
   3  *
   4  * Copyright 1995 David S. Miller (davem@caip.rutgers.edu)
   5  */
   6 
   7 /*
   8  * I hate traps on the sparc, grrr...
   9  */
  10 
  11 #include <linux/sched.h>  /* for jiffies */
  12 #include <linux/kernel.h>
  13 #include <linux/config.h>
  14 #include <linux/signal.h>
  15 
  16 #include <asm/delay.h>
  17 #include <asm/system.h>
  18 #include <asm/ptrace.h>
  19 #include <asm/oplib.h>
  20 #include <asm/page.h>
  21 #include <asm/pgtable.h>
  22 #include <asm/kdebug.h>
  23 #include <asm/unistd.h>
  24 #include <asm/traps.h>
  25 #include <asm/smp.h>
  26 
  27 /* #define TRAP_DEBUG */
  28 
  29 struct trap_trace_entry {
  30         unsigned long pc;
  31         unsigned long type;
  32 };
  33 
  34 int trap_curbuf = 0;
  35 struct trap_trace_entry trapbuf[1024];
  36 
  37 void syscall_trace_entry(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  38 {
  39         printk("%s[%d]: ", current->comm, current->pid);
  40         printk("scall<%d> (could be %d)\n", (int) regs->u_regs[UREG_G1],
  41                (int) regs->u_regs[UREG_I0]);
  42 }
  43 
  44 void syscall_trace_exit(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46 }
  47 
  48 void sun4m_nmi(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  49 {
  50         unsigned long afsr, afar;
  51 
  52         printk("Aieee: sun4m NMI received!\n");
  53         /* XXX HyperSparc hack XXX */
  54         __asm__ __volatile__("mov 0x500, %%g1\n\t"
  55                              "lda [%%g1] 0x4, %0\n\t"
  56                              "mov 0x600, %%g1\n\t"
  57                              "lda [%%g1] 0x4, %1\n\t" :
  58                              "=r" (afsr), "=r" (afar));
  59         printk("afsr=%08lx afar=%08lx\n", afsr, afar);
  60         printk("you lose buddy boy...\n");
  61         show_regs(regs);
  62         prom_halt();
  63 }
  64 
  65 void die_if_kernel(char *str, struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  66 {
  67         unsigned long i;
  68         unsigned long *pc;
  69 
  70         /* Amuse the user. */
  71         printk(
  72 "              \\|/ ____ \\|/\n"
  73 "              \"@'/ ,. \\`@\"\n"
  74 "              /_| \\__/ |_\\\n"
  75 "                 \\__U_/\n");
  76 
  77         printk("%s(%d): %s\n", current->comm, current->pid, str);
  78         show_regs(regs);
  79 #if CONFIG_AP1000
  80         ap_panic();
  81 #endif
  82         printk("Instruction DUMP:");
  83         pc = (unsigned long *) regs->pc;
  84         for(i = -3; i < 6; i++)
  85                 printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
  86         printk("\n");
  87         if(regs->psr & PSR_PS)
  88                 do_exit(SIGKILL);
  89         do_exit(SIGSEGV);
  90 }
  91 
  92 void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
     /* [previous][next][first][last][top][bottom][index][help] */
  93 {
  94         if(type < 0x80) {
  95                 /* Sun OS's puke from bad traps, Linux survives! */
  96                 printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
  97                 die_if_kernel("Whee... Hello Mr. Penguin", current->tss.kregs);
  98         }       
  99         if(type == SP_TRAP_SBPT) {
 100                 send_sig(SIGTRAP, current, 1);
 101                 return;
 102         }
 103         current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80);
 104         current->tss.sig_address = pc;
 105         send_sig(SIGILL, current, 1);
 106 }
 107 
 108 void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 109                             unsigned long psr)
 110 {
 111         if(psr & PSR_PS)
 112                 die_if_kernel("Kernel illegal instruction", regs);
 113 #ifdef TRAP_DEBUG
 114         printk("Ill instr. at pc=%08lx instruction is %08lx\n",
 115                regs->pc, *(unsigned long *)regs->pc);
 116 #endif
 117         current->tss.sig_address = pc;
 118         current->tss.sig_desc = SUBSIG_ILLINST;
 119         send_sig(SIGILL, current, 1);
 120 }
 121 
 122 void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 123                          unsigned long psr)
 124 {
 125         if(psr & PSR_PS)
 126                 die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
 127         current->tss.sig_address = pc;
 128         current->tss.sig_desc = SUBSIG_PRIVINST;
 129         send_sig(SIGILL, current, 1);
 130 }
 131 
 132 /* XXX User may want to be allowed to do this. XXX */
 133 
 134 void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 135                             unsigned long psr)
 136 {
 137         if(regs->psr & PSR_PS) {
 138                 printk("KERNEL MNA at pc %08lx npc %08lx called by %08lx\n", pc, npc,
 139                        regs->u_regs[UREG_RETPC]);
 140                 die_if_kernel("BOGUS", regs);
 141                 /* die_if_kernel("Kernel MNA access", regs); */
 142         }
 143         current->tss.sig_address = pc;
 144         current->tss.sig_desc = SUBSIG_PRIVINST;
 145         send_sig(SIGBUS, current, 1);
 146 }
 147 
 148 extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
 149                    void *fpqueue, unsigned long *fpqdepth);
 150 extern void fpload(unsigned long *fpregs, unsigned long *fsr);
 151 
 152 static unsigned long init_fsr = 0x0UL;
 153 static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
 154                 { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
 155                   ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
 156                   ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
 157                   ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
 158 
 159 void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 160                  unsigned long psr)
 161 {
 162         /* Sanity check... */
 163         if(psr & PSR_PS)
 164                 die_if_kernel("Kernel gets FloatingPenguinUnit disabled trap", regs);
 165 
 166         put_psr(get_psr() | PSR_EF);    /* Allow FPU ops. */
 167         regs->psr |= PSR_EF;
 168 #ifndef __SMP__
 169         if(last_task_used_math == current)
 170                 return;
 171         if(last_task_used_math) {
 172                 /* Other processes fpu state, save away */
 173                 struct task_struct *fptask = last_task_used_math;
 174                 fpsave(&fptask->tss.float_regs[0], &fptask->tss.fsr,
 175                        &fptask->tss.fpqueue[0], &fptask->tss.fpqdepth);
 176         }
 177         last_task_used_math = current;
 178         if(current->used_math) {
 179                 fpload(&current->tss.float_regs[0], &current->tss.fsr);
 180         } else {
 181                 /* Set initial sane state. */
 182                 fpload(&init_fregs[0], &init_fsr);
 183                 current->used_math = 1;
 184         }
 185 #else
 186         if(!current->used_math) {
 187                 fpload(&init_fregs[0], &init_fsr);
 188                 current->used_math = 1;
 189         } else {
 190                 fpload(&current->tss.float_regs[0], &current->tss.fsr);
 191         }
 192         current->flags |= PF_USEDFPU;
 193 #endif
 194 }
 195 
 196 static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
 197 static unsigned long fake_fsr;
 198 static unsigned long fake_queue[32] __attribute__ ((aligned (8)));
 199 static unsigned long fake_depth;
 200 
 201 void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 202                  unsigned long psr)
 203 {
 204         static calls = 0;
 205 #ifndef __SMP__
 206         struct task_struct *fpt = last_task_used_math;
 207 #else
 208         struct task_struct *fpt = current;
 209 #endif
 210 
 211         put_psr(get_psr() | PSR_EF);
 212         /* If nobody owns the fpu right now, just clear the
 213          * error into our fake static buffer and hope it don't
 214          * happen again.  Thank you crashme...
 215          */
 216 #ifndef __SMP__
 217         if(!fpt) {
 218 #else
 219         if(!(fpt->flags & PF_USEDFPU)) {
 220 #endif
 221                 fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
 222                 regs->psr &= ~PSR_EF;
 223                 return;
 224         }
 225         fpsave(&fpt->tss.float_regs[0], &fpt->tss.fsr,
 226                &fpt->tss.fpqueue[0], &fpt->tss.fpqdepth);
 227         fpt->tss.sig_address = pc;
 228         fpt->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */
 229 #ifdef __SMP__
 230         fpt->flags &= ~PF_USEDFPU;
 231 #endif
 232         if(psr & PSR_PS) {
 233                 /* The first fsr store/load we tried trapped,
 234                  * the second one will not (we hope).
 235                  */
 236                 printk("WARNING: FPU exception from kernel mode. at pc=%08lx\n",
 237                        regs->pc);
 238                 regs->pc = regs->npc;
 239                 regs->npc += 4;
 240                 calls++;
 241                 if(calls > 2)
 242                         die_if_kernel("Too many Penguin-FPU traps from kernel mode",
 243                                       regs);
 244                 return;
 245         }
 246         send_sig(SIGFPE, fpt, 1);
 247 #ifndef __SMP__
 248         last_task_used_math = NULL;
 249 #endif
 250         regs->psr &= ~PSR_EF;
 251         if(calls > 0)
 252                 calls=0;
 253 }
 254 
 255 void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 256                          unsigned long psr)
 257 {
 258         if(psr & PSR_PS)
 259                 die_if_kernel("Penguin overflow trap from kernel mode", regs);
 260         current->tss.sig_address = pc;
 261         current->tss.sig_desc = SUBSIG_TAG; /* as good as any */
 262         send_sig(SIGEMT, current, 1);
 263 }
 264 
 265 void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 266                        unsigned long psr)
 267 {
 268 #ifdef TRAP_DEBUG
 269         printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
 270                pc, npc, psr);
 271 #endif
 272         if(psr & PSR_PS)
 273                 panic("Tell me what a watchpoint trap is, and I'll then deal "
 274                       "with such a beast...");
 275 }
 276 
 277 void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 278                        unsigned long psr)
 279 {
 280 #ifdef TRAP_DEBUG
 281         printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
 282                pc, npc, psr);
 283 #endif
 284         send_sig(SIGILL, current, 1);
 285 }
 286 
 287 void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 288                         unsigned long psr)
 289 {
 290         send_sig(SIGILL, current, 1);
 291 }
 292 
 293 void handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 294                       unsigned long psr)
 295 {
 296 #ifdef TRAP_DEBUG
 297         printk("Unimplemented FLUSH Exception at PC %08lx NPC %08lx PSR %08lx\n",
 298                pc, npc, psr);
 299 #endif
 300         printk("INSTRUCTION=%08lx\n", *((unsigned long *) regs->pc));
 301         send_sig(SIGILL, current, 1);
 302 }
 303 
 304 void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 305                          unsigned long psr)
 306 {
 307 #ifdef TRAP_DEBUG
 308         printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
 309                pc, npc, psr);
 310 #endif
 311         send_sig(SIGILL, current, 1);
 312 }
 313 
 314 void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 315                        unsigned long psr)
 316 {
 317         send_sig(SIGILL, current, 1);
 318 }
 319 
 320 /* Since we have our mappings set up, on multiprocessors we can spin them
 321  * up here so that timer interrupts work during initialization.
 322  */
 323 
 324 extern void sparc_cpu_startup(void);
 325 
 326 extern int linux_num_cpus;
 327 extern ctxd_t *srmmu_ctx_table_phys;
 328 
 329 int linux_smp_still_initting;
 330 unsigned int thiscpus_tbr;
 331 int thiscpus_mid;
 332 
 333 void trap_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 334 {
 335 }

/* [previous][next][first][last][top][bottom][index][help] */