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

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