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/mm.h>
  12 #include <linux/sched.h>
  13 #include <linux/tty.h>
  14 
  15 #include <asm/unaligned.h>
  16 
  17 void die_if_kernel(char * str, struct pt_regs * regs, long err)
     /* [previous][next][first][last][top][bottom][index][help] */
  18 {
  19         long i;
  20         unsigned long sp;
  21         unsigned int * pc;
  22 
  23         if (regs->ps & 8)
  24                 return;
  25         printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
  26         sp = (unsigned long) (regs+1);
  27         printk("pc = %lx ps = %04lx\n", regs->pc, regs->ps);
  28         printk("rp = %lx sp = %lx\n", regs->r26, sp);
  29         printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
  30                 regs->r0, regs->r1, regs->r2, regs->r3);
  31         printk("r8=%lx\n", regs->r8);
  32         printk("r16=%lx r17=%lx r18=%lx r19=%lx\n",
  33                 regs->r16, regs->r17, regs->r18, regs->r19);
  34         printk("r20=%lx r21=%lx r22=%lx r23=%lx\n",
  35                 regs->r20, regs->r21, regs->r22, regs->r23);
  36         printk("r24=%lx r25=%lx r26=%lx r27=%lx\n",
  37                 regs->r24, regs->r25, regs->r26, regs->r27);
  38         printk("r28=%lx r29=%lx r30=%lx\n",
  39                 regs->r28, regs->gp, sp);
  40         printk("Code:");
  41         pc = (unsigned int *) regs->pc;
  42         for (i = -3; i < 6; i++)
  43                 printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
  44         printk("\n");
  45         for (i = 0 ; i < 5000000000 ; i++)
  46                 /* pause */;
  47         halt();
  48 }
  49 
  50 asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
     /* [previous][next][first][last][top][bottom][index][help] */
  51         unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5,
  52         struct pt_regs regs)
  53 {
  54         printk("Arithmetic trap: %02lx %016lx\n", summary, write_mask);
  55         die_if_kernel("Arithmetic fault", &regs, 0);
  56         send_sig(SIGFPE, current, 1);
  57 }
  58 
  59 asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
     /* [previous][next][first][last][top][bottom][index][help] */
  60         unsigned long a3, unsigned long a4, unsigned long a5,
  61         struct pt_regs regs)
  62 {
  63         extern int ptrace_cancel_bpt (struct task_struct *who);
  64 
  65         die_if_kernel("Instruction fault", &regs, type);
  66         switch (type) {
  67               case 0: /* breakpoint */
  68                 if (ptrace_cancel_bpt(current)) {
  69                         regs.pc -= 4;   /* make pc point to former bpt */
  70                 }
  71                 send_sig(SIGTRAP, current, 1);
  72                 break;
  73 
  74               case 1: /* bugcheck */
  75               case 2: /* gentrap */
  76               case 3: /* FEN fault */
  77               case 4: /* opDEC */
  78                 send_sig(SIGILL, current, 1);
  79                 break;
  80 
  81               default:
  82                 panic("do_entIF: unexpected instruction-fault type");
  83         }
  84 }
  85 
  86 /*
  87  * entUna has a different register layout to be reasonably simple. It
  88  * needs access to all the integer registers (the kernel doesn't use
  89  * fp-regs), and it needs to have them in order for simpler access.
  90  *
  91  * Due to the non-standard register layout (and because we don't want
  92  * to handle floating-point regs), user-mode unaligned accesses are
  93  * handled separately by do_entUnaUser below.
  94  *
  95  * Oh, btw, we don't handle the "gp" register correctly, but if we fault
  96  * on a gp-register unaligned load/store, something is _very_ wrong
  97  * in the kernel anyway..
  98  */
  99 struct allregs {
 100         unsigned long regs[32];
 101         unsigned long ps, pc, gp, a0, a1, a2;
 102 };
 103 
 104 struct unaligned_stat {
 105         unsigned long count, va, pc;
 106 } unaligned[2];
 107 
 108 asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
     /* [previous][next][first][last][top][bottom][index][help] */
 109         unsigned long a3, unsigned long a4, unsigned long a5,
 110         struct allregs regs)
 111 {
 112         static int cnt = 0;
 113         static long last_time = 0;
 114 
 115         if (cnt >= 5 && jiffies - last_time > 5*HZ) {
 116                 cnt = 0;
 117         }
 118         if (++cnt < 5) {
 119                 printk("kernel: unaligned trap at %016lx: %p %lx %ld\n",
 120                        regs.pc - 4, va, opcode, reg);
 121         }
 122         last_time = jiffies;
 123 
 124         ++unaligned[0].count;
 125         unaligned[0].va = (unsigned long) va - 4;
 126         unaligned[0].pc = regs.pc;
 127 
 128         /* $16-$18 are PAL-saved, and are offset by 19 entries */
 129         if (reg >= 16 && reg <= 18)
 130                 reg += 19;
 131         switch (opcode) {
 132                 case 0x28: /* ldl */
 133                         *(reg+regs.regs) = (int) ldl_u(va);
 134                         return;
 135                 case 0x29: /* ldq */
 136                         *(reg+regs.regs) = ldq_u(va);
 137                         return;
 138                 case 0x2c: /* stl */
 139                         stl_u(*(reg+regs.regs), va);
 140                         return;
 141                 case 0x2d: /* stq */
 142                         stq_u(*(reg+regs.regs), va);
 143                         return;
 144         }
 145         printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
 146                 regs.pc, va, opcode, reg);
 147         do_exit(SIGSEGV);
 148 }
 149 
 150 /*
 151  * Handle user-level unaligned fault.  Handling user-level unaligned
 152  * faults is *extremely* slow and produces nasty messages.  A user
 153  * program *should* fix unaligned faults ASAP.
 154  *
 155  * Notice that we have (almost) the regular kernel stack layout here,
 156  * so finding the appropriate registers is a little more difficult
 157  * than in the kernel case.
 158  *
 159  * Finally, we handle regular integer load/stores only.  In
 160  * particular, load-linked/store-conditionally and floating point
 161  * load/stores are not supported.  The former make no sense with
 162  * unaligned faults (they are guaranteed to fail) and I don't think
 163  * the latter will occur in any decent program.
 164  */
 165 asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg,
     /* [previous][next][first][last][top][bottom][index][help] */
 166                               unsigned long * frame)
 167 {
 168         long dir, size;
 169         unsigned long *reg_addr, *pc_addr, usp, zero = 0;
 170         static int cnt = 0;
 171         static long last_time = 0;
 172 
 173         pc_addr = frame + 7 + 20 + 1;                   /* pc in PAL frame */
 174 
 175         if (cnt >= 5 && jiffies - last_time > 5*HZ) {
 176                 cnt = 0;
 177         }
 178         if (++cnt < 5) {
 179                 printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
 180                        current->comm, current->pid,
 181                        *pc_addr - 4, va, opcode, reg);
 182         }
 183         last_time = jiffies;
 184 
 185         ++unaligned[1].count;
 186         unaligned[1].va = (unsigned long) va - 4;
 187         unaligned[1].pc = *pc_addr;
 188 
 189         dir = VERIFY_READ;
 190         if (opcode > 0x29) {
 191                 /* it's a stl or stq */
 192                 dir = VERIFY_WRITE;
 193         }
 194         size = 4;
 195         if (opcode & 1) {
 196                 /* it's a quadword op */
 197                 size = 8;
 198         }
 199         if (verify_area(dir, va, size)) {
 200                 *pc_addr -= 4;  /* make pc point to faulting insn */
 201                 send_sig(SIGSEGV, current, 1);
 202                 return;
 203         }
 204 
 205         reg_addr = frame;
 206         if (reg < 9) {
 207                 reg_addr += 7 + reg;                    /* v0-t7 in SAVE_ALL frame */
 208         } else if (reg < 16) {
 209                 reg_addr += (reg - 9);                  /* s0-s6 in entUna frame */
 210         } else if (reg < 19) {
 211                 reg_addr += 7 + 20 + 3 + (reg - 16);    /* a0-a2 in PAL frame */
 212         } else if (reg < 29) {
 213                 reg_addr += 7 + 9 + (reg - 19);         /* a3-at in SAVE_ALL frame */
 214         } else {
 215                 switch (reg) {
 216                         case 29:                        /* gp in PAL frame */
 217                                 reg_addr += 7 + 20 + 2;
 218                                 break;
 219                         case 30:                        /* usp in PAL regs */
 220                                 usp = rdusp();
 221                                 reg_addr = &usp;
 222                                 break;
 223                         case 31:                        /* zero "register" */
 224                                 reg_addr = &zero;
 225                                 break;
 226                 }
 227         }
 228 
 229         switch (opcode) {
 230                 case 0x28: *reg_addr = (int) ldl_u(va); break;  /* ldl */
 231                 case 0x29: *reg_addr = ldq_u(va);       break;  /* ldq */
 232                 case 0x2c: stl_u(*reg_addr, va);        break;  /* stl */
 233                 case 0x2d: stq_u(*reg_addr, va);        break;  /* stq */
 234                 default:
 235                         *pc_addr -= 4;  /* make pc point to faulting insn */
 236                         send_sig(SIGBUS, current, 1);
 237                         return;
 238         }
 239 
 240         if (reg == 30 && dir == VERIFY_WRITE) {
 241                 wrusp(usp);
 242         } 
 243 }
 244 
 245 /*
 246  * DEC means people to use the "retsys" instruction for return from
 247  * a system call, but they are clearly misguided about this. We use
 248  * "rti" in all cases, and fill in the stack with the return values.
 249  * That should make signal handling etc much cleaner.
 250  *
 251  * Even more horribly, DEC doesn't allow system calls from kernel mode.
 252  * "Security" features letting the user do something the kernel can't
 253  * are a thinko. DEC palcode is strange. The PAL-code designers probably
 254  * got terminally tainted by VMS at some point.
 255  */
 256 asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
     /* [previous][next][first][last][top][bottom][index][help] */
 257         unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs)
 258 {
 259         if (regs.r0 != 112)
 260           printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
 261         return -1;
 262 }
 263 
 264 extern asmlinkage void entMM(void);
 265 extern asmlinkage void entIF(void);
 266 extern asmlinkage void entArith(void);
 267 extern asmlinkage void entUna(void);
 268 extern asmlinkage void entSys(void);
 269 
 270 void trap_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 271 {
 272         unsigned long gptr;
 273 
 274         /*
 275          * Tell PAL-code what global pointer we want in the kernel..
 276          */
 277         __asm__("br %0,___tmp\n"
 278                 "___tmp:\tldgp %0,0(%0)"
 279                 : "=r" (gptr));
 280         wrkgp(gptr);
 281 
 282         wrent(entArith, 1);
 283         wrent(entMM, 2);
 284         wrent(entIF, 3);
 285         wrent(entUna, 4);
 286         wrent(entSys, 5);
 287 }

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