📄 traps.c
字号:
" .gprel32 4b\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) : "r"(va), "r"(una_reg(reg)), "0"(0)); if (error) goto got_exception; return; case 0x2d: /* stq */ __asm__ __volatile__( "1: ldq_u %2,7(%5)\n" "2: ldq_u %1,0(%5)\n" " insqh %6,%5,%4\n" " insql %6,%5,%3\n" " mskqh %2,%5,%2\n" " mskql %1,%5,%1\n" " or %2,%4,%2\n" " or %1,%3,%1\n" "3: stq_u %2,7(%5)\n" "4: stq_u %1,0(%5)\n" "5:\n" ".section __ex_table,\"a\"\n\t" " .gprel32 1b\n" " lda %2,5b-1b(%0)\n" " .gprel32 2b\n" " lda %1,5b-2b(%0)\n" " .gprel32 3b\n" " lda $31,5b-3b(%0)\n" " .gprel32 4b\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) : "r"(va), "r"(una_reg(reg)), "0"(0)); if (error) goto got_exception; return; } lock_kernel(); printk("Bad unaligned kernel access at %016lx: %p %lx %ld\n", pc, va, opcode, reg); do_exit(SIGSEGV);got_exception: /* Ok, we caught the exception, but we don't want it. Is there someone to pass it along to? */ if ((fixup = search_exception_table(pc, regs.gp)) != 0) { unsigned long newpc; newpc = fixup_exception(una_reg, fixup, pc); printk("Forwarding unaligned exception at %lx (%lx)\n", pc, newpc); (®s)->pc = newpc; return; } /* * Yikes! No one to forward the exception to. * Since the registers are in a weird format, dump them ourselves. */ lock_kernel(); printk("%s(%d): unhandled unaligned exception\n", current->comm, current->pid); printk("pc = [<%016lx>] ra = [<%016lx>] ps = %04lx\n", pc, una_reg(26), regs.ps); printk("r0 = %016lx r1 = %016lx r2 = %016lx\n", una_reg(0), una_reg(1), una_reg(2)); printk("r3 = %016lx r4 = %016lx r5 = %016lx\n", una_reg(3), una_reg(4), una_reg(5)); printk("r6 = %016lx r7 = %016lx r8 = %016lx\n", una_reg(6), una_reg(7), una_reg(8)); printk("r9 = %016lx r10= %016lx r11= %016lx\n", una_reg(9), una_reg(10), una_reg(11)); printk("r12= %016lx r13= %016lx r14= %016lx\n", una_reg(12), una_reg(13), una_reg(14)); printk("r15= %016lx\n", una_reg(15)); printk("r16= %016lx r17= %016lx r18= %016lx\n", una_reg(16), una_reg(17), una_reg(18)); printk("r19= %016lx r20= %016lx r21= %016lx\n", una_reg(19), una_reg(20), una_reg(21)); printk("r22= %016lx r23= %016lx r24= %016lx\n", una_reg(22), una_reg(23), una_reg(24)); printk("r25= %016lx r27= %016lx r28= %016lx\n", una_reg(25), una_reg(27), una_reg(28)); printk("gp = %016lx sp = %p\n", regs.gp, ®s+1); dik_show_code((unsigned int *)pc); dik_show_trace((unsigned long *)(®s+1)); if (current->thread.flags & (1UL << 63)) { printk("die_if_kernel recursion detected.\n"); sti(); while (1); } current->thread.flags |= (1UL << 63); do_exit(SIGSEGV);}/* * Convert an s-floating point value in memory format to the * corresponding value in register format. The exponent * needs to be remapped to preserve non-finite values * (infinities, not-a-numbers, denormals). */static inline unsigned longs_mem_to_reg (unsigned long s_mem){ unsigned long frac = (s_mem >> 0) & 0x7fffff; unsigned long sign = (s_mem >> 31) & 0x1; unsigned long exp_msb = (s_mem >> 30) & 0x1; unsigned long exp_low = (s_mem >> 23) & 0x7f; unsigned long exp; exp = (exp_msb << 10) | exp_low; /* common case */ if (exp_msb) { if (exp_low == 0x7f) { exp = 0x7ff; } } else { if (exp_low == 0x00) { exp = 0x000; } else { exp |= (0x7 << 7); } } return (sign << 63) | (exp << 52) | (frac << 29);}/* * Convert an s-floating point value in register format to the * corresponding value in memory format. */static inline unsigned longs_reg_to_mem (unsigned long s_reg){ return ((s_reg >> 62) << 30) | ((s_reg << 5) >> 34);}/* * Handle user-level unaligned fault. Handling user-level unaligned * faults is *extremely* slow and produces nasty messages. A user * program *should* fix unaligned faults ASAP. * * Notice that we have (almost) the regular kernel stack layout here, * so finding the appropriate registers is a little more difficult * than in the kernel case. * * Finally, we handle regular integer load/stores only. In * particular, load-linked/store-conditionally and floating point * load/stores are not supported. The former make no sense with * unaligned faults (they are guaranteed to fail) and I don't think * the latter will occur in any decent program. * * Sigh. We *do* have to handle some FP operations, because GCC will * uses them as temporary storage for integer memory to memory copies. * However, we need to deal with stt/ldt and sts/lds only. */#define OP_INT_MASK ( 1L << 0x28 | 1L << 0x2c /* ldl stl */ \ | 1L << 0x29 | 1L << 0x2d /* ldq stq */ \ | 1L << 0x0c | 1L << 0x0d /* ldwu stw */ \ | 1L << 0x0a | 1L << 0x0e ) /* ldbu stb */#define OP_WRITE_MASK ( 1L << 0x26 | 1L << 0x27 /* sts stt */ \ | 1L << 0x2c | 1L << 0x2d /* stl stq */ \ | 1L << 0x0d | 1L << 0x0e ) /* stw stb */#define R(x) ((size_t) &((struct pt_regs *)0)->x)static int unauser_reg_offsets[32] = { R(r0), R(r1), R(r2), R(r3), R(r4), R(r5), R(r6), R(r7), R(r8), /* r9 ... r15 are stored in front of regs. */ -56, -48, -40, -32, -24, -16, -8, R(r16), R(r17), R(r18), R(r19), R(r20), R(r21), R(r22), R(r23), R(r24), R(r25), R(r26), R(r27), R(r28), R(gp), 0, 0};#undef Rasmlinkage voiddo_entUnaUser(void * va, unsigned long opcode, unsigned long reg, struct pt_regs *regs){ static int cnt = 0; static long last_time = 0; unsigned long tmp1, tmp2, tmp3, tmp4; unsigned long fake_reg, *reg_addr = &fake_reg; unsigned long uac_bits; long error; /* Check the UAC bits to decide what the user wants us to do with the unaliged access. */ uac_bits = (current->thread.flags >> UAC_SHIFT) & UAC_BITMASK; if (!(uac_bits & UAC_NOPRINT)) { if (cnt >= 5 && jiffies - last_time > 5*HZ) { cnt = 0; } if (++cnt < 5) { printk("%s(%d): unaligned trap at %016lx: %p %lx %ld\n", current->comm, current->pid, regs->pc - 4, va, opcode, reg); } last_time = jiffies; } if (uac_bits & UAC_SIGBUS) { goto give_sigbus; } if (uac_bits & UAC_NOFIX) { /* Not sure why you'd want to use this, but... */ return; } /* Don't bother reading ds in the access check since we already know that this came from the user. Also rely on the fact that the page at TASK_SIZE is unmapped and so can't be touched anyway. */ if (!__access_ok((unsigned long)va, 0, USER_DS)) goto give_sigsegv; ++unaligned[1].count; unaligned[1].va = (unsigned long)va; unaligned[1].pc = regs->pc - 4; if ((1L << opcode) & OP_INT_MASK) { /* it's an integer load/store */ if (reg < 30) { reg_addr = (unsigned long *) ((char *)regs + unauser_reg_offsets[reg]); } else if (reg == 30) { /* usp in PAL regs */ fake_reg = rdusp(); } else { /* zero "register" */ fake_reg = 0; } } /* We don't want to use the generic get/put unaligned macros as we want to trap exceptions. Only if we actually get an exception will we decide whether we should have caught it. */ switch (opcode) { case 0x0c: /* ldwu */ __asm__ __volatile__( "1: ldq_u %1,0(%3)\n" "2: ldq_u %2,1(%3)\n" " extwl %1,%3,%1\n" " extwh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" " .gprel32 1b\n" " lda %1,3b-1b(%0)\n" " .gprel32 2b\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) : "r"(va), "0"(0)); if (error) goto give_sigsegv; *reg_addr = tmp1|tmp2; break; case 0x22: /* lds */ __asm__ __volatile__( "1: ldq_u %1,0(%3)\n" "2: ldq_u %2,3(%3)\n" " extll %1,%3,%1\n" " extlh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" " .gprel32 1b\n" " lda %1,3b-1b(%0)\n" " .gprel32 2b\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) : "r"(va), "0"(0)); if (error) goto give_sigsegv; alpha_write_fp_reg(reg, s_mem_to_reg((int)(tmp1|tmp2))); return; case 0x23: /* ldt */ __asm__ __volatile__( "1: ldq_u %1,0(%3)\n" "2: ldq_u %2,7(%3)\n" " extql %1,%3,%1\n" " extqh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" " .gprel32 1b\n" " lda %1,3b-1b(%0)\n" " .gprel32 2b\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) : "r"(va), "0"(0)); if (error) goto give_sigsegv; alpha_write_fp_reg(reg, tmp1|tmp2); return; case 0x28: /* ldl */ __asm__ __volatile__( "1: ldq_u %1,0(%3)\n" "2: ldq_u %2,3(%3)\n" " extll %1,%3,%1\n" " extlh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" " .gprel32 1b\n" " lda %1,3b-1b(%0)\n" " .gprel32 2b\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) : "r"(va), "0"(0)); if (error) goto give_sigsegv; *reg_addr = (int)(tmp1|tmp2); break; case 0x29: /* ldq */ __asm__ __volatile__( "1: ldq_u %1,0(%3)\n" "2: ldq_u %2,7(%3)\n" " extql %1,%3,%1\n" " extqh %2,%3,%2\n" "3:\n" ".section __ex_table,\"a\"\n" " .gprel32 1b\n" " lda %1,3b-1b(%0)\n" " .gprel32 2b\n" " lda %2,3b-2b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2) : "r"(va), "0"(0)); if (error) goto give_sigsegv; *reg_addr = tmp1|tmp2; break; /* Note that the store sequences do not indicate that they change memory because it _should_ be affecting nothing in this context. (Otherwise we have other, much larger, problems.) */ case 0x0d: /* stw */ __asm__ __volatile__( "1: ldq_u %2,1(%5)\n" "2: ldq_u %1,0(%5)\n" " inswh %6,%5,%4\n" " inswl %6,%5,%3\n" " mskwh %2,%5,%2\n" " mskwl %1,%5,%1\n" " or %2,%4,%2\n" " or %1,%3,%1\n" "3: stq_u %2,1(%5)\n" "4: stq_u %1,0(%5)\n" "5:\n" ".section __ex_table,\"a\"\n" " .gprel32 1b\n" " lda %2,5b-1b(%0)\n" " .gprel32 2b\n" " lda %1,5b-2b(%0)\n" " .gprel32 3b\n" " lda $31,5b-3b(%0)\n" " .gprel32 4b\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) : "r"(va), "r"(*reg_addr), "0"(0)); if (error) goto give_sigsegv; return; case 0x26: /* sts */ fake_reg = s_reg_to_mem(alpha_read_fp_reg(reg)); /* FALLTHRU */ case 0x2c: /* stl */ __asm__ __volatile__( "1: ldq_u %2,3(%5)\n" "2: ldq_u %1,0(%5)\n" " inslh %6,%5,%4\n" " insll %6,%5,%3\n" " msklh %2,%5,%2\n" " mskll %1,%5,%1\n" " or %2,%4,%2\n" " or %1,%3,%1\n" "3: stq_u %2,3(%5)\n" "4: stq_u %1,0(%5)\n" "5:\n" ".section __ex_table,\"a\"\n" " .gprel32 1b\n" " lda %2,5b-1b(%0)\n" " .gprel32 2b\n" " lda %1,5b-2b(%0)\n" " .gprel32 3b\n" " lda $31,5b-3b(%0)\n" " .gprel32 4b\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) : "r"(va), "r"(*reg_addr), "0"(0)); if (error) goto give_sigsegv; return; case 0x27: /* stt */ fake_reg = alpha_read_fp_reg(reg); /* FALLTHRU */ case 0x2d: /* stq */ __asm__ __volatile__( "1: ldq_u %2,7(%5)\n" "2: ldq_u %1,0(%5)\n" " insqh %6,%5,%4\n" " insql %6,%5,%3\n" " mskqh %2,%5,%2\n" " mskql %1,%5,%1\n" " or %2,%4,%2\n" " or %1,%3,%1\n" "3: stq_u %2,7(%5)\n" "4: stq_u %1,0(%5)\n" "5:\n" ".section __ex_table,\"a\"\n\t" " .gprel32 1b\n" " lda %2,5b-1b(%0)\n" " .gprel32 2b\n" " lda %1,5b-2b(%0)\n" " .gprel32 3b\n" " lda $31,5b-3b(%0)\n" " .gprel32 4b\n" " lda $31,5b-4b(%0)\n" ".previous" : "=r"(error), "=&r"(tmp1), "=&r"(tmp2), "=&r"(tmp3), "=&r"(tmp4) : "r"(va), "r"(*reg_addr), "0"(0)); if (error) goto give_sigsegv; return; default: /* What instruction were you trying to use, exactly? */ goto give_sigbus; } /* Only integer loads should get here; everyone else returns early. */ if (reg == 30) wrusp(fake_reg); return;give_sigsegv: regs->pc -= 4; /* make pc point to faulting insn */ send_sig(SIGSEGV, current, 1); return;give_sigbus: regs->pc -= 4; send_sig(SIGBUS, current, 1); return;}/* * Unimplemented system calls. */asmlinkage longalpha_ni_syscall(unsigned long a0, unsigned long a1, unsigned long a2, unsigned long a3, unsigned long a4, unsigned long a5, struct pt_regs regs){ /* We only get here for OSF system calls, minus #112; the rest go to sys_ni_syscall. */#if 0 printk("<sc %ld(%lx,%lx,%lx)>", regs.r0, a0, a1, a2);#endif return -ENOSYS;}voidtrap_init(void){ /* Tell PAL-code what global pointer we want in the kernel. */ register unsigned long gptr __asm__("$29"); wrkgp(gptr); wrent(entArith, 1); wrent(entMM, 2); wrent(entIF, 3); wrent(entUna, 4); wrent(entSys, 5); wrent(entDbg, 6); /* Hack for Multia (UDB) and JENSEN: some of their SRMs have * a bug in the handling of the opDEC fault. Fix it up if so. */ if (implver() == IMPLVER_EV4) { opDEC_check(); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -