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. s_mem_to_reg
  6. s_reg_to_mem
  7. do_entUnaUser
  8. do_entSys
  9. 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/config.h>
  12 #include <linux/mm.h>
  13 #include <linux/sched.h>
  14 #include <linux/tty.h>
  15 
  16 #include <asm/gentrap.h>
  17 #include <asm/segment.h>
  18 #include <asm/unaligned.h>
  19 
  20 void die_if_kernel(char * str, struct pt_regs * regs, long err)
     /* [previous][next][first][last][top][bottom][index][help] */
  21 {
  22         long i;
  23         unsigned long sp;
  24         unsigned int * pc;
  25 
  26         if (regs->ps & 8)
  27                 return;
  28         printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err);
  29         sp = (unsigned long) (regs+1);
  30         printk("pc = [<%lx>] ps = %04lx\n", regs->pc, regs->ps);
  31         printk("rp = [<%lx>] sp = %lx\n", regs->r26, sp);
  32         printk("r0=%lx r1=%lx r2=%lx r3=%lx\n",
  33                 regs->r0, regs->r1, regs->r2, regs->r3);
  34         printk("r8=%lx\n", regs->r8);
  35         printk("r16=%lx r17=%lx r18=%lx r19=%lx\n",
  36                 regs->r16, regs->r17, regs->r18, regs->r19);
  37         printk("r20=%lx r21=%lx r22=%lx r23=%lx\n",
  38                 regs->r20, regs->r21, regs->r22, regs->r23);
  39         printk("r24=%lx r25=%lx r26=%lx r27=%lx\n",
  40                 regs->r24, regs->r25, regs->r26, regs->r27);
  41         printk("r28=%lx r29=%lx r30=%lx\n",
  42                 regs->r28, regs->gp, sp);
  43         printk("Code:");
  44         pc = (unsigned int *) regs->pc;
  45         for (i = -3; i < 6; i++)
  46                 printk("%c%08x%c",i?' ':'<',pc[i],i?' ':'>');
  47         printk("\n");
  48         do_exit(SIGSEGV);
  49 }
  50 
  51 asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask,
     /* [previous][next][first][last][top][bottom][index][help] */
  52                             unsigned long a2, unsigned long a3,
  53                             unsigned long a4, unsigned long a5,
  54                             struct pt_regs regs)
  55 {
  56         if ((summary & 1)) {
  57                 extern long alpha_fp_emul_imprecise (struct pt_regs * regs,
  58                                                      unsigned long write_mask);
  59                 /*
  60                  * Software-completion summary bit is set, so try to
  61                  * emulate the instruction.
  62                  */
  63                 if (alpha_fp_emul_imprecise(&regs, write_mask)) {
  64                         return;         /* emulation was successful */
  65                 }
  66         }
  67         printk("%s: arithmetic trap at %016lx: %02lx %016lx\n",
  68                 current->comm, regs.pc, summary, write_mask);
  69         die_if_kernel("Arithmetic fault", &regs, 0);
  70         send_sig(SIGFPE, current, 1);
  71 }
  72 
  73 asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2,
     /* [previous][next][first][last][top][bottom][index][help] */
  74                          unsigned long a3, unsigned long a4, unsigned long a5,
  75                          struct pt_regs regs)
  76 {
  77         extern int ptrace_cancel_bpt (struct task_struct *who);
  78 
  79         die_if_kernel("Instruction fault", &regs, type);
  80         switch (type) {
  81               case 0: /* breakpoint */
  82                 if (ptrace_cancel_bpt(current)) {
  83                         regs.pc -= 4;   /* make pc point to former bpt */
  84                 }
  85                 send_sig(SIGTRAP, current, 1);
  86                 break;
  87 
  88               case 2: /* gentrap */
  89                 /*
  90                  * The translation from the gentrap error code into a
  91                  * siginfo structure (see /usr/include/sys/siginfo.h)
  92                  * is missing as Linux does not presently support the
  93                  * siginfo argument that is normally passed to a
  94                  * signal handler.
  95                  */
  96                 switch ((long) regs.r16) {
  97                       case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF:
  98                       case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV:
  99                       case GEN_FLTINE:
 100                         send_sig(SIGFPE, current, 1);
 101                         break;
 102 
 103                       case GEN_DECOVF:
 104                       case GEN_DECDIV:
 105                       case GEN_DECINV:
 106                       case GEN_ROPRAND:
 107                       case GEN_ASSERTERR:
 108                       case GEN_NULPTRERR:
 109                       case GEN_STKOVF:
 110                       case GEN_STRLENERR:
 111                       case GEN_SUBSTRERR:
 112                       case GEN_RANGERR:
 113                       case GEN_SUBRNG:
 114                       case GEN_SUBRNG1:
 115                       case GEN_SUBRNG2:
 116                       case GEN_SUBRNG3:
 117                       case GEN_SUBRNG4:
 118                       case GEN_SUBRNG5:
 119                       case GEN_SUBRNG6:
 120                       case GEN_SUBRNG7:
 121                         send_sig(SIGILL, current, 1);
 122                         break;
 123                 }
 124                 break;
 125 
 126               case 1: /* bugcheck */
 127               case 3: /* FEN fault */
 128                 send_sig(SIGILL, current, 1);
 129                 break;
 130 
 131               case 4: /* opDEC */
 132 #ifdef CONFIG_ALPHA_NEED_ROUNDING_EMULATION
 133                 {
 134                         extern long alpha_fp_emul (unsigned long pc);
 135                         unsigned int opcode;
 136 
 137                         /* get opcode of faulting instruction: */
 138                         opcode = get_user((__u32*)(regs.pc - 4)) >> 26;
 139                         if (opcode == 0x16) {
 140                                 /*
 141                                  * It's a FLTI instruction, emulate it
 142                                  * (we don't do no stinkin' VAX fp...)
 143                                  */
 144                                 if (!alpha_fp_emul(regs.pc - 4))
 145                                         send_sig(SIGFPE, current, 1);
 146                                 break;
 147                         }
 148                 }
 149 #endif
 150                 send_sig(SIGILL, current, 1);
 151                 break;
 152 
 153               default:
 154                 panic("do_entIF: unexpected instruction-fault type");
 155         }
 156 }
 157 
 158 /*
 159  * entUna has a different register layout to be reasonably simple. It
 160  * needs access to all the integer registers (the kernel doesn't use
 161  * fp-regs), and it needs to have them in order for simpler access.
 162  *
 163  * Due to the non-standard register layout (and because we don't want
 164  * to handle floating-point regs), user-mode unaligned accesses are
 165  * handled separately by do_entUnaUser below.
 166  *
 167  * Oh, btw, we don't handle the "gp" register correctly, but if we fault
 168  * on a gp-register unaligned load/store, something is _very_ wrong
 169  * in the kernel anyway..
 170  */
 171 struct allregs {
 172         unsigned long regs[32];
 173         unsigned long ps, pc, gp, a0, a1, a2;
 174 };
 175 
 176 struct unaligned_stat {
 177         unsigned long count, va, pc;
 178 } unaligned[2];
 179 
 180 asmlinkage void do_entUna(void * va, unsigned long opcode, unsigned long reg,
     /* [previous][next][first][last][top][bottom][index][help] */
 181         unsigned long a3, unsigned long a4, unsigned long a5,
 182         struct allregs regs)
 183 {
 184         static int cnt = 0;
 185         static long last_time = 0;
 186 
 187         if (cnt >= 5 && jiffies - last_time > 5*HZ) {
 188                 cnt = 0;
 189         }
 190         if (++cnt < 5) {
 191                 printk("kernel: unaligned trap at %016lx: %p %lx %ld\n",
 192                        regs.pc - 4, va, opcode, reg);
 193         }
 194         last_time = jiffies;
 195 
 196         ++unaligned[0].count;
 197         unaligned[0].va = (unsigned long) va - 4;
 198         unaligned[0].pc = regs.pc;
 199 
 200         /* $16-$18 are PAL-saved, and are offset by 19 entries */
 201         if (reg >= 16 && reg <= 18)
 202                 reg += 19;
 203         switch (opcode) {
 204                 case 0x28: /* ldl */
 205                         *(reg+regs.regs) = (int) ldl_u(va);
 206                         return;
 207                 case 0x29: /* ldq */
 208                         *(reg+regs.regs) = ldq_u(va);
 209                         return;
 210                 case 0x2c: /* stl */
 211                         stl_u(*(reg+regs.regs), va);
 212                         return;
 213                 case 0x2d: /* stq */
 214                         stq_u(*(reg+regs.regs), va);
 215                         return;
 216         }
 217         printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n",
 218                 regs.pc, va, opcode, reg);
 219         do_exit(SIGSEGV);
 220 }
 221 
 222 /*
 223  * Convert an s-floating point value in memory format to the
 224  * corresponding value in register format.  The exponent
 225  * needs to be remapped to preserve non-finite values
 226  * (infinities, not-a-numbers, denormals).
 227  */
 228 static inline unsigned long s_mem_to_reg (unsigned long s_mem)
     /* [previous][next][first][last][top][bottom][index][help] */
 229 {
 230         unsigned long frac    = (s_mem >>  0) & 0x7fffff;
 231         unsigned long sign    = (s_mem >> 31) & 0x1;
 232         unsigned long exp_msb = (s_mem >> 30) & 0x1;
 233         unsigned long exp_low = (s_mem >> 23) & 0x7f;
 234         unsigned long exp;
 235 
 236         exp = (exp_msb << 10) | exp_low;        /* common case */
 237         if (exp_msb) {
 238                 if (exp_low == 0x7f) {
 239                         exp = 0x3ff;
 240                 }
 241         } else {
 242                 if (exp_low == 0x00) {
 243                         exp = 0x000;
 244                 } else {
 245                         exp |= (0x7 << 8);
 246                 }
 247         }
 248         return (sign << 63) | (exp << 52) | (frac << 29);
 249 }
 250 
 251 /*
 252  * Convert an s-floating point value in register format to the
 253  * corresponding value in memory format.
 254  */
 255 static inline unsigned long s_reg_to_mem (unsigned long s_reg)
     /* [previous][next][first][last][top][bottom][index][help] */
 256 {
 257         return ((s_reg >> 62) << 30) | ((s_reg << 5) >> 34);
 258 }
 259 
 260 /*
 261  * Handle user-level unaligned fault.  Handling user-level unaligned
 262  * faults is *extremely* slow and produces nasty messages.  A user
 263  * program *should* fix unaligned faults ASAP.
 264  *
 265  * Notice that we have (almost) the regular kernel stack layout here,
 266  * so finding the appropriate registers is a little more difficult
 267  * than in the kernel case.
 268  *
 269  * Finally, we handle regular integer load/stores only.  In
 270  * particular, load-linked/store-conditionally and floating point
 271  * load/stores are not supported.  The former make no sense with
 272  * unaligned faults (they are guaranteed to fail) and I don't think
 273  * the latter will occur in any decent program.
 274  *
 275  * Sigh. We *do* have to handle some FP operations, because GCC will
 276  * uses them as temporary storage for integer memory to memory copies.
 277  * However, we need to deal with stt/ldt and sts/lds only.
 278  */
 279 asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg,
     /* [previous][next][first][last][top][bottom][index][help] */
 280                               unsigned long * frame)
 281 {
 282         long dir, size;
 283         unsigned long *reg_addr, *pc_addr, usp, zero = 0;
 284         static int cnt = 0;
 285         static long last_time = 0;
 286         extern void alpha_write_fp_reg (unsigned long reg, unsigned long val);
 287         extern unsigned long alpha_read_fp_reg (unsigned long reg);
 288 
 289         pc_addr = frame + 7 + 20 + 1;                   /* pc in PAL frame */
 290 
 291         if (cnt >= 5 && jiffies - last_time > 5*HZ) {
 292                 cnt = 0;
 293         }
 294         if (++cnt < 5) {
 295                 printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n",
 296                        current->comm, current->pid,
 297                        *pc_addr - 4, va, opcode, reg);
 298         }
 299         last_time = jiffies;
 300 
 301         ++unaligned[1].count;
 302         unaligned[1].va = (unsigned long) va - 4;
 303         unaligned[1].pc = *pc_addr;
 304 
 305         dir = VERIFY_READ;
 306         if (opcode & 0x4) {
 307                 /* it's a stl, stq, stt, or sts */
 308                 dir = VERIFY_WRITE;
 309         }
 310         size = 4;
 311         if (opcode & 0x1) {
 312                 /* it's a quadword op */
 313                 size = 8;
 314         }
 315         if (verify_area(dir, va, size)) {
 316                 *pc_addr -= 4;  /* make pc point to faulting insn */
 317                 send_sig(SIGSEGV, current, 1);
 318                 return;
 319         }
 320 
 321         reg_addr = frame;
 322         if (opcode >= 0x28) {
 323                 /* it's an integer load/store */
 324                 if (reg < 9) {
 325                         reg_addr += 7 + reg;                    /* v0-t7 in SAVE_ALL frame */
 326                 } else if (reg < 16) {
 327                         reg_addr += (reg - 9);                  /* s0-s6 in entUna frame */
 328                 } else if (reg < 19) {
 329                         reg_addr += 7 + 20 + 3 + (reg - 16);    /* a0-a2 in PAL frame */
 330                 } else if (reg < 29) {
 331                         reg_addr += 7 + 9 + (reg - 19);         /* a3-at in SAVE_ALL frame */
 332                 } else {
 333                         switch (reg) {
 334                               case 29:                          /* gp in PAL frame */
 335                                 reg_addr += 7 + 20 + 2;
 336                                 break;
 337                               case 30:                          /* usp in PAL regs */
 338                                 usp = rdusp();
 339                                 reg_addr = &usp;
 340                                 break;
 341                               case 31:                          /* zero "register" */
 342                                 reg_addr = &zero;
 343                                 break;
 344                         }
 345                 }
 346         }
 347 
 348         switch (opcode) {
 349               case 0x22:                                                /* lds */
 350                 alpha_write_fp_reg(reg, s_mem_to_reg(ldl_u(va)));
 351                 break;
 352               case 0x26:                                                /* lds */
 353                 alpha_write_fp_reg(reg, s_reg_to_mem(ldl_u(va)));
 354                 break;
 355 
 356               case 0x23: alpha_write_fp_reg(reg, ldq_u(va)); break;     /* ldt */
 357               case 0x27: stq_u(alpha_read_fp_reg(reg), va);  break;     /* stt */
 358 
 359               case 0x28: *reg_addr = (int) ldl_u(va);        break;     /* ldl */
 360               case 0x29: *reg_addr = ldq_u(va);              break;     /* ldq */
 361               case 0x2c: stl_u(*reg_addr, va);               break;     /* stl */
 362               case 0x2d: stq_u(*reg_addr, va);               break;     /* stq */
 363               default:
 364                 *pc_addr -= 4;  /* make pc point to faulting insn */
 365                 send_sig(SIGBUS, current, 1);
 366                 return;
 367         }
 368 
 369         if (opcode >= 0x28 && reg == 30 && dir == VERIFY_WRITE) {
 370                 wrusp(usp);
 371         } 
 372 }
 373 
 374 /*
 375  * DEC means people to use the "retsys" instruction for return from
 376  * a system call, but they are clearly misguided about this. We use
 377  * "rti" in all cases, and fill in the stack with the return values.
 378  * That should make signal handling etc much cleaner.
 379  *
 380  * Even more horribly, DEC doesn't allow system calls from kernel mode.
 381  * "Security" features letting the user do something the kernel can't
 382  * are a thinko. DEC palcode is strange. The PAL-code designers probably
 383  * got terminally tainted by VMS at some point.
 384  */
 385 asmlinkage long do_entSys(unsigned long a0, unsigned long a1, unsigned long a2,
     /* [previous][next][first][last][top][bottom][index][help] */
 386         unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs)
 387 {
 388         if (regs.r0 != 112)
 389           printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);
 390         return -1;
 391 }
 392 
 393 extern asmlinkage void entMM(void);
 394 extern asmlinkage void entIF(void);
 395 extern asmlinkage void entArith(void);
 396 extern asmlinkage void entUna(void);
 397 extern asmlinkage void entSys(void);
 398 
 399 void trap_init(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 400 {
 401         unsigned long gptr;
 402 
 403         /*
 404          * Tell PAL-code what global pointer we want in the kernel..
 405          */
 406         __asm__("br %0,___tmp\n"
 407                 "___tmp:\tldgp %0,0(%0)"
 408                 : "=r" (gptr));
 409         wrkgp(gptr);
 410 
 411         wrent(entArith, 1);
 412         wrent(entMM, 2);
 413         wrent(entIF, 3);
 414         wrent(entUna, 4);
 415         wrent(entSys, 5);
 416 }

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