root/arch/alpha/kernel/traps.c

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

DEFINITIONS

This source file includes following definitions.
  1. die_if_kernel
  2. do_entArith
  3. do_entIF
  4. do_entUna
  5. do_entUnaUser
  6. do_entSys
  7. trap_init

   1 /*
   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/sched.h>
  12 #include <linux/tty.h>
  13 
  14 #include <asm/unaligned.h>
  15 
  16 void die_if_kernel(char * str, struct pt_regs * regs, long err)
     /* [previous][next][first][last][top][bottom][index][help] */
  17 {
  18         long i;
  19         unsigned long sp;
  20         unsigned int * pc;
  21 
  22         if (regs->ps & 8)
  23                 return;
  24         printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
  25         sp = (unsigned long) (regs+1);
  26         printk("pc = %lx ps = %04lx\n", regs->pc, regs->ps);
  27         printk("rp = %lx sp = %lx\n", regs->r26, sp);
  28         printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
  29                 regs->r0, regs->r1, regs->r2, regs->r3);
  30         printk("r8=%lx\n", regs->r8);
  31         printk("r16=%lx r17=%lx r18=%lx r19=%lx\n",
  32                 regs->r16, regs->r17, regs->r18, regs->r19);
  33         printk("r20=%lx r21=%lx r22=%lx r23=%lx\n",
  34                 regs->r20, regs->r21, regs->r22, regs->r23);
  35         printk("r24=%lx r25=%lx r26=%lx r27=%lx\n",
  36                 regs->r24, regs->r25, regs->r26, regs->r27);
  37         printk("r28=%lx r29=%lx r30=%lx\n",
  38                 regs->r28, regs->gp, sp);
  39         printk("Code:");
  40         pc = (unsigned int *) regs->pc;
  41         for (i = -3; i < 6; i++)
  42                 printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
  43         printk("\n");
  44         for (i = 0 ; i < 5000000000 ; i++)
  45                 /* pause */;
  46         halt();
  47 }
  48 
  49 asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
     /* [previous][next][first][last][top][bottom][index][help] */
  50         unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5,
  51         struct pt_regs regs)
  52 {
  53         printk("Arithmetic trap: %02lx %016lx\n", summary, write_mask);
  54         die_if_kernel("Arithmetic fault", &regs, 0);
  55         send_sig(SIGFPE, current, 1);
  56 }
  57 
  58 asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
     /* [previous][next][first][last][top][bottom][index][help] */
  59         unsigned long a3, unsigned long a4, unsigned long a5,
  60         struct pt_regs regs)
  61 {
  62         extern int ptrace_cancel_bpt (struct task_struct *who);
  63 
  64         die_if_kernel("Instruction fault", &regs, type);
  65         switch (type) {
  66               case 0: /* breakpoint */
  67                 if (ptrace_cancel_bpt(current)) {
  68                         regs.pc -= 4;   /* make pc point to former bpt */
  69                 }
  70                 send_sig(SIGTRAP, current, 1);
  71                 break;
  72 
  73               case 1: /* bugcheck */
  74               case 2: /* gentrap */
  75               case 3: /* FEN fault */
  76               case 4: /* opDEC */
  77                 send_sig(SIGILL, current, 1);
  78                 break;
  79 
  80               default:
  81                 panic("do_entIF: unexpected instruction-fault type");
  82         }
  83 }
  84 
  85 /*
  86  * entUna has a different register layout to be reasonably simple. It
  87  * needs access to all the integer registers (the kernel doesn't use
  88  * fp-regs), and it needs to have them in order for simpler access.
  89  *
  90  * Due to the non-standard register layout (and because we don't want
  91  * to handle floating-point regs), user-mode unaligned accesses are
  92  * handled separately by do_entUnaUser below.
  93  *
  94  * Oh, btw, we don't handle the "gp" register correctly, but if we fault
  95  * on a gp-register unaligned load/store, something is _very_ wrong
  96  * in the kernel anyway..
  97  */
  98 struct allregs {
  99         unsigned long regs[32];
 100         unsigned long ps, pc, gp, a0, a1, a2;
 101 };
 102 
 103 struct unaligned_stat {
 104         unsigned long count, va, pc;
 105 } unaligned;
 106 
 107 asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
     /* [previous][next][first][last][top][bottom][index][help] */
 108         unsigned long a3, unsigned long a4, unsigned long a5,
 109         struct allregs regs)
 110 {
 111         static int cnt = 0;
 112 
 113         if (++cnt < 5)
 114                 printk("Unaligned trap at %016lx: %p %lx %ld\n",
 115                         regs.pc, va, opcode, reg);
 116 
 117         ++unaligned.count;
 118         unaligned.va = (unsigned long) va - 4;
 119         unaligned.pc = regs.pc;
 120 
 121         /* $16-$18 are PAL-saved, and are offset by 19 entries */
 122         if (reg >= 16 && reg <= 18)
 123                 reg += 19;
 124         switch (opcode) {
 125                 case 0x28: /* ldl */
 126                         *(reg+regs.regs) = (int) ldl_u(va);
 127                         return;
 128                 case 0x29: /* ldq */
 129                         *(reg+regs.regs) = ldq_u(va);
 130                         return;
 131                 case 0x2c: /* stl */
 132                         stl_u(*(reg+regs.regs), va);
 133                         return;
 134                 case 0x2d: /* stq */
 135                         stq_u(*(reg+regs.regs), va);
 136                         return;
 137         }
 138         printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
 139                 regs.pc, va, opcode, reg);
 140         do_exit(SIGSEGV);
 141 }
 142 
 143 /*
 144  * Handle user-level unaligned fault.  For now, simply send a
 145  * SIGBUS---there should be little reason for users not wanting to
 146  * fix their code instead.  Notice that we have the regular kernel
 147  * stack layout here, so finding the appropriate registers is a little
 148  * more difficult than in the kernel case.  Also, we'd need to do
 149  * a "verify_area()" before accessing memory on behalf of the user.
 150  */
 151 asmlinkage void do_entUnaUser(void *va, unsigned long opcode, unsigned long reg,
     /* [previous][next][first][last][top][bottom][index][help] */
 152                               unsigned long a3, unsigned long a4, unsigned long a5,
 153                               struct pt_regs regs)
 154 {
 155         regs.pc -= 4;   /* make pc point to faulting insn */
 156         send_sig(SIGBUS, current, 1);
 157 }
 158 
 159 /*
 160  * DEC means people to use the "retsys" instruction for return from
 161  * a system call, but they are clearly misguided about this. We use
 162  * "rti" in all cases, and fill in the stack with the return values.
 163  * That should make signal handling etc much cleaner.
 164  *
 165  * Even more horribly, DEC doesn't allow system calls from kernel mode.
 166  * "Security" features letting the user do something the kernel can't
 167  * are a thinko. DEC palcode is strange. The PAL-code designers probably
 168  * got terminally tainted by VMS at some point.
 169  */
 170 asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
     /* [previous][next][first][last][top][bottom][index][help] */
 171         unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs)
 172 {
 173         if (regs.r0 != 112)
 174           printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
 175         return -1;
 176 }
 177 
 178 extern asmlinkage void entMM(void);
 179 extern asmlinkage void entIF(void);
 180 extern asmlinkage void entArith(void);
 181 extern asmlinkage void entUna(void);
 182 extern asmlinkage void entSys(void);
 183 
 184 void trap_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 185 {
 186         unsigned long gptr;
 187 
 188         /*
 189          * Tell PAL-code what global pointer we want in the kernel..
 190          */
 191         __asm__("br %0,___tmp\n"
 192                 "___tmp:\tldgp %0,0(%0)"
 193                 : "=r" (gptr));
 194         wrkgp(gptr);
 195 
 196         wrent(entArith, 1);
 197         wrent(entMM, 2);
 198         wrent(entIF, 3);
 199         wrent(entUna, 4);
 200         wrent(entSys, 5);
 201 }

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