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. die_if_kernel
  4. do_hw_interrupt
  5. do_illegal_instruction
  6. do_priv_instruction
  7. do_memaccess_unaligned
  8. do_fpd_trap
  9. do_fpe_trap
  10. handle_tag_overflow
  11. handle_watchpoint
  12. handle_reg_access
  13. handle_cp_disabled
  14. handle_bad_flush
  15. handle_cp_exception
  16. handle_hw_divzero
  17. trap_init

   1 /* $Id: traps.c,v 1.32 1996/03/01 07:16:08 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/signal.h>
  14 
  15 #include <asm/delay.h>
  16 #include <asm/system.h>
  17 #include <asm/ptrace.h>
  18 #include <asm/oplib.h>
  19 #include <asm/page.h>
  20 #include <asm/pgtable.h>
  21 #include <asm/mp.h>
  22 #include <asm/kdebug.h>
  23 #include <asm/unistd.h>
  24 
  25 struct trap_trace_entry {
  26         unsigned long pc;
  27         unsigned long type;
  28 };
  29 
  30 int trap_curbuf = 0;
  31 struct trap_trace_entry trapbuf[1024];
  32 
  33 void syscall_trace_entry(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  34 {
  35         printk("%s[%d]: ", current->comm, current->pid);
  36         printk("scall<%d> (could be %d)\n", (int) regs->u_regs[UREG_G1],
  37                (int) regs->u_regs[UREG_I0]);
  38 }
  39 
  40 void syscall_trace_exit(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  41 {
  42 }
  43 
  44 void die_if_kernel(char *str, struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  45 {
  46         unsigned long i;
  47         unsigned long *pc;
  48 
  49         if(regs->psr & PSR_PS)
  50                 do_exit(SIGKILL);
  51         printk("%s(%d): %s\n", current->comm, current->pid, str);
  52         show_regs(regs);
  53         printk("Instruction DUMP:");
  54         pc = (unsigned long *) regs->pc;
  55         for(i = -3; i < 6; i++)
  56                 printk("%c%08lx%c",i?' ':'<',pc[i],i?' ':'>');
  57         printk("\n");
  58         do_exit(SIGSEGV);
  59 }
  60 
  61 void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc)
     /* [previous][next][first][last][top][bottom][index][help] */
  62 {
  63         if(type < 0x80) {
  64                 /* Sun OS's puke from bad traps, Linux survives! */
  65                 printk("Unimplemented Sparc TRAP, type = %02lx\n", type);
  66                 panic("Whee... Hello Mr. Penguin");
  67         }       
  68         current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80);
  69         current->tss.sig_address = pc;
  70         send_sig(SIGILL, current, 1);
  71 }
  72 
  73 void do_illegal_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
  74                             unsigned long psr)
  75 {
  76         if(psr & PSR_PS)
  77                 die_if_kernel("Kernel illegal instruction", regs);
  78         current->tss.sig_address = pc;
  79         current->tss.sig_desc = SUBSIG_ILLINST;
  80         send_sig(SIGILL, current, 1);
  81 }
  82 
  83 void do_priv_instruction(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
  84                          unsigned long psr)
  85 {
  86         if(psr & PSR_PS)
  87                 die_if_kernel("Penguin instruction from Penguin mode??!?!", regs);
  88         current->tss.sig_address = pc;
  89         current->tss.sig_desc = SUBSIG_PRIVINST;
  90         send_sig(SIGILL, current, 1);
  91 }
  92 
  93 /* XXX User may want to be allowed to do this. XXX */
  94 
  95 void do_memaccess_unaligned(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
  96                             unsigned long psr)
  97 {
  98         if(regs->psr & PSR_PS)
  99                 die_if_kernel("Kernel MNA access", regs);
 100         current->tss.sig_address = pc;
 101         current->tss.sig_desc = SUBSIG_PRIVINST;
 102         send_sig(SIGBUS, current, 1);
 103 }
 104 
 105 extern void fpsave(unsigned long *fpregs, unsigned long *fsr,
 106                    void *fpqueue, unsigned long *fpqdepth);
 107 extern void fpload(unsigned long *fpregs, unsigned long *fsr);
 108 
 109 static unsigned long init_fsr = 0x0UL;
 110 static unsigned long init_fregs[32] __attribute__ ((aligned (8))) =
 111                 { ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
 112                   ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
 113                   ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL,
 114                   ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL, ~0UL };
 115 
 116 void do_fpd_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 117                  unsigned long psr)
 118 {
 119         /* Sanity check... */
 120         if(psr & PSR_PS)
 121                 die_if_kernel("Kernel gets Penguin-FPU disabled trap", regs);
 122 
 123         put_psr(get_psr() | PSR_EF);    /* Allow FPU ops. */
 124         regs->psr |= PSR_EF;
 125         if(last_task_used_math == current)
 126                 return;
 127         if(last_task_used_math) {
 128                 /* Other processes fpu state, save away */
 129                 struct task_struct *fptask = last_task_used_math;
 130                 fpsave(&fptask->tss.float_regs[0], &fptask->tss.fsr,
 131                        &fptask->tss.fpqueue[0], &fptask->tss.fpqdepth);
 132         }
 133         last_task_used_math = current;
 134         if(current->used_math) {
 135                 fpload(&current->tss.float_regs[0], &current->tss.fsr);
 136         } else {
 137                 /* Set initial sane state. */
 138                 fpload(&init_fregs[0], &init_fsr);
 139                 current->used_math = 1;
 140         }
 141 }
 142 
 143 static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
 144 static unsigned long fake_fsr;
 145 static unsigned long fake_queue[32] __attribute__ ((aligned (8)));
 146 static unsigned long fake_depth;
 147 
 148 void do_fpe_trap(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 149                  unsigned long psr)
 150 {
 151         static calls = 0;
 152         struct task_struct *fpt = last_task_used_math;
 153 
 154         put_psr(get_psr() | PSR_EF);
 155         /* If nobody owns the fpu right now, just clear the
 156          * error into our fake static buffer and hope it don't
 157          * happen again.  Thank you crashme...
 158          */
 159         if(!fpt) {
 160                 fpsave(&fake_regs[0], &fake_fsr, &fake_queue[0], &fake_depth);
 161                 regs->psr &= ~PSR_EF;
 162                 return;
 163         }
 164         fpsave(&fpt->tss.float_regs[0], &fpt->tss.fsr,
 165                &fpt->tss.fpqueue[0], &fpt->tss.fpqdepth);
 166         last_task_used_math->tss.sig_address = pc;
 167         last_task_used_math->tss.sig_desc = SUBSIG_FPERROR; /* as good as any */
 168         if(psr & PSR_PS) {
 169                 /* The first fsr store/load we tried trapped,
 170                  * the second one will not (we hope).
 171                  */
 172                 printk("WARNING: FPU exception from kernel mode. at pc=%08lx\n",
 173                        regs->pc);
 174                 regs->pc = regs->npc;
 175                 regs->npc += 4;
 176                 calls++;
 177                 if(calls > 2)
 178                         die_if_kernel("Too many Penguin-FPU traps from kernel mode",
 179                                       regs);
 180                 return;
 181         }
 182         send_sig(SIGFPE, last_task_used_math, 1);
 183         last_task_used_math = NULL;
 184         regs->psr &= ~PSR_EF;
 185         if(calls > 0)
 186                 calls=0;
 187 }
 188 
 189 void handle_tag_overflow(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 190                          unsigned long psr)
 191 {
 192         if(psr & PSR_PS)
 193                 die_if_kernel("Penguin overflow trap from kernel mode", regs);
 194         current->tss.sig_address = pc;
 195         current->tss.sig_desc = SUBSIG_TAG; /* as good as any */
 196         send_sig(SIGEMT, current, 1);
 197 }
 198 
 199 void handle_watchpoint(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 200                        unsigned long psr)
 201 {
 202         printk("Watchpoint detected at PC %08lx NPC %08lx PSR %08lx\n",
 203                pc, npc, psr);
 204         if(psr & PSR_PS)
 205                 panic("Tell me what a watchpoint trap is, and I'll then deal "
 206                       "with such a beast...");
 207 }
 208 
 209 void handle_reg_access(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 210                        unsigned long psr)
 211 {
 212         printk("Register Access Exception at PC %08lx NPC %08lx PSR %08lx\n",
 213                pc, npc, psr);
 214         send_sig(SIGILL, current, 1);
 215 }
 216 
 217 void handle_cp_disabled(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 218                         unsigned long psr)
 219 {
 220         send_sig(SIGILL, current, 1);
 221 }
 222 
 223 void handle_bad_flush(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 224                       unsigned long psr)
 225 {
 226         printk("Unimplemented FLUSH Exception at PC %08lx NPC %08lx PSR %08lx\n",
 227                pc, npc, psr);
 228         send_sig(SIGILL, current, 1);
 229 }
 230 
 231 void handle_cp_exception(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 232                          unsigned long psr)
 233 {
 234         printk("Co-Processor Exception at PC %08lx NPC %08lx PSR %08lx\n",
 235                pc, npc, psr);
 236         send_sig(SIGILL, current, 1);
 237 }
 238 
 239 void handle_hw_divzero(struct pt_regs *regs, unsigned long pc, unsigned long npc,
     /* [previous][next][first][last][top][bottom][index][help] */
 240                        unsigned long psr)
 241 {
 242         printk("Divide By Zero Exception at PC %08lx NPC %08lx PSR %08lx\n",
 243                pc, npc, psr);
 244         send_sig(SIGILL, current, 1);
 245 }
 246 
 247 /* Since we have our mappings set up, on multiprocessors we can spin them
 248  * up here so that timer interrupts work during initialization.
 249  */
 250 
 251 extern void sparc_cpu_startup(void);
 252 
 253 extern int linux_num_cpus;
 254 extern pgd_t **srmmu_context_table;
 255 
 256 int linux_smp_still_initting;
 257 unsigned int thiscpus_tbr;
 258 int thiscpus_mid;
 259 
 260 void trap_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 261 {
 262         struct linux_prom_registers ctx_reg;
 263         int i;
 264 
 265         if(linux_num_cpus == 1) {
 266                 printk("trap_init: Uniprocessor detected.\n");
 267                 return;
 268         }
 269         if(sparc_cpu_model != sun4m) {
 270                 prom_printf("trap_init: Multiprocessor on a non-sun4m! Aieee...\n");
 271                 prom_printf("trap_init: Cannot continue, bailing out.\n");
 272                 prom_halt();
 273         }
 274         /* Ok, we are on a sun4m with multiple cpu's */
 275         prom_printf("trap_init: Multiprocessor detected, initiating CPU-startup. cpus=%d\n",
 276                linux_num_cpus);
 277         linux_smp_still_initting = 1;
 278         ctx_reg.which_io = 0x0;  /* real ram */
 279         ctx_reg.phys_addr = (char *) (((unsigned long) srmmu_context_table) - PAGE_OFFSET);
 280         ctx_reg.reg_size = 0x0;
 281         /* This basically takes every cpu, loads up our Linux context table
 282          * into it's context table pointer register, inits it at the low level
 283          * and then makes it spin in an endless loop...
 284          */
 285         for(i=0; i<linux_num_cpus; i++) {
 286                 if((linux_cpus[i].mid & (~8)) != 0x0) {
 287                         static int cpuid = 0;
 288                         cpuid = (linux_cpus[i].mid & (~8));
 289                         percpu_table[cpuid].cpu_is_alive = 0;
 290                         thiscpus_mid = linux_cpus[i].mid;
 291                         thiscpus_tbr = (unsigned int)
 292                                 percpu_table[cpuid].trap_table;
 293                         prom_startcpu(linux_cpus[i].prom_node, &ctx_reg, 0x0,
 294                                       (char *) sparc_cpu_startup);
 295                         prom_printf("Waiting for cpu %d to start up...\n", i);
 296                         while(percpu_table[cpuid].cpu_is_alive == 0) {
 297                                 static int counter = 0;
 298                                 counter++;
 299                                 if(counter>200)
 300                                         break;
 301                                 __delay(200000);
 302                         }
 303                 }
 304         }
 305 
 306         linux_smp_still_initting = 1;
 307 }

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