|
@@ -269,3 +269,193 @@ do_entIF(unsigned long type, struct pt_regs *regs)
|
|
|
send_sig_info(SIGTRAP, &info, current);
|
|
|
return;
|
|
|
|
|
|
+ case 1: /* bugcheck */
|
|
|
+ info.si_signo = SIGTRAP;
|
|
|
+ info.si_errno = 0;
|
|
|
+ info.si_code = __SI_FAULT;
|
|
|
+ info.si_addr = (void __user *) regs->pc;
|
|
|
+ info.si_trapno = 0;
|
|
|
+ send_sig_info(SIGTRAP, &info, current);
|
|
|
+ return;
|
|
|
+
|
|
|
+ case 2: /* gentrap */
|
|
|
+ info.si_addr = (void __user *) regs->pc;
|
|
|
+ info.si_trapno = regs->r16;
|
|
|
+ switch ((long) regs->r16) {
|
|
|
+ case GEN_INTOVF:
|
|
|
+ signo = SIGFPE;
|
|
|
+ code = FPE_INTOVF;
|
|
|
+ break;
|
|
|
+ case GEN_INTDIV:
|
|
|
+ signo = SIGFPE;
|
|
|
+ code = FPE_INTDIV;
|
|
|
+ break;
|
|
|
+ case GEN_FLTOVF:
|
|
|
+ signo = SIGFPE;
|
|
|
+ code = FPE_FLTOVF;
|
|
|
+ break;
|
|
|
+ case GEN_FLTDIV:
|
|
|
+ signo = SIGFPE;
|
|
|
+ code = FPE_FLTDIV;
|
|
|
+ break;
|
|
|
+ case GEN_FLTUND:
|
|
|
+ signo = SIGFPE;
|
|
|
+ code = FPE_FLTUND;
|
|
|
+ break;
|
|
|
+ case GEN_FLTINV:
|
|
|
+ signo = SIGFPE;
|
|
|
+ code = FPE_FLTINV;
|
|
|
+ break;
|
|
|
+ case GEN_FLTINE:
|
|
|
+ signo = SIGFPE;
|
|
|
+ code = FPE_FLTRES;
|
|
|
+ break;
|
|
|
+ case GEN_ROPRAND:
|
|
|
+ signo = SIGFPE;
|
|
|
+ code = __SI_FAULT;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case GEN_DECOVF:
|
|
|
+ case GEN_DECDIV:
|
|
|
+ case GEN_DECINV:
|
|
|
+ case GEN_ASSERTERR:
|
|
|
+ case GEN_NULPTRERR:
|
|
|
+ case GEN_STKOVF:
|
|
|
+ case GEN_STRLENERR:
|
|
|
+ case GEN_SUBSTRERR:
|
|
|
+ case GEN_RANGERR:
|
|
|
+ case GEN_SUBRNG:
|
|
|
+ case GEN_SUBRNG1:
|
|
|
+ case GEN_SUBRNG2:
|
|
|
+ case GEN_SUBRNG3:
|
|
|
+ case GEN_SUBRNG4:
|
|
|
+ case GEN_SUBRNG5:
|
|
|
+ case GEN_SUBRNG6:
|
|
|
+ case GEN_SUBRNG7:
|
|
|
+ default:
|
|
|
+ signo = SIGTRAP;
|
|
|
+ code = __SI_FAULT;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ info.si_signo = signo;
|
|
|
+ info.si_errno = 0;
|
|
|
+ info.si_code = code;
|
|
|
+ info.si_addr = (void __user *) regs->pc;
|
|
|
+ send_sig_info(signo, &info, current);
|
|
|
+ return;
|
|
|
+
|
|
|
+ case 4: /* opDEC */
|
|
|
+ if (implver() == IMPLVER_EV4) {
|
|
|
+ long si_code;
|
|
|
+
|
|
|
+ /* The some versions of SRM do not handle
|
|
|
+ the opDEC properly - they return the PC of the
|
|
|
+ opDEC fault, not the instruction after as the
|
|
|
+ Alpha architecture requires. Here we fix it up.
|
|
|
+ We do this by intentionally causing an opDEC
|
|
|
+ fault during the boot sequence and testing if
|
|
|
+ we get the correct PC. If not, we set a flag
|
|
|
+ to correct it every time through. */
|
|
|
+ regs->pc += opDEC_fix;
|
|
|
+
|
|
|
+ /* EV4 does not implement anything except normal
|
|
|
+ rounding. Everything else will come here as
|
|
|
+ an illegal instruction. Emulate them. */
|
|
|
+ si_code = alpha_fp_emul(regs->pc - 4);
|
|
|
+ if (si_code == 0)
|
|
|
+ return;
|
|
|
+ if (si_code > 0) {
|
|
|
+ info.si_signo = SIGFPE;
|
|
|
+ info.si_errno = 0;
|
|
|
+ info.si_code = si_code;
|
|
|
+ info.si_addr = (void __user *) regs->pc;
|
|
|
+ send_sig_info(SIGFPE, &info, current);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ break;
|
|
|
+
|
|
|
+ case 3: /* FEN fault */
|
|
|
+ /* Irritating users can call PAL_clrfen to disable the
|
|
|
+ FPU for the process. The kernel will then trap in
|
|
|
+ do_switch_stack and undo_switch_stack when we try
|
|
|
+ to save and restore the FP registers.
|
|
|
+
|
|
|
+ Given that GCC by default generates code that uses the
|
|
|
+ FP registers, PAL_clrfen is not useful except for DoS
|
|
|
+ attacks. So turn the bleeding FPU back on and be done
|
|
|
+ with it. */
|
|
|
+ current_thread_info()->pcb.flags |= 1;
|
|
|
+ __reload_thread(¤t_thread_info()->pcb);
|
|
|
+ return;
|
|
|
+
|
|
|
+ case 5: /* illoc */
|
|
|
+ default: /* unexpected instruction-fault type */
|
|
|
+ ;
|
|
|
+ }
|
|
|
+
|
|
|
+ info.si_signo = SIGILL;
|
|
|
+ info.si_errno = 0;
|
|
|
+ info.si_code = ILL_ILLOPC;
|
|
|
+ info.si_addr = (void __user *) regs->pc;
|
|
|
+ send_sig_info(SIGILL, &info, current);
|
|
|
+}
|
|
|
+
|
|
|
+/* There is an ifdef in the PALcode in MILO that enables a
|
|
|
+ "kernel debugging entry point" as an unprivileged call_pal.
|
|
|
+
|
|
|
+ We don't want to have anything to do with it, but unfortunately
|
|
|
+ several versions of MILO included in distributions have it enabled,
|
|
|
+ and if we don't put something on the entry point we'll oops. */
|
|
|
+
|
|
|
+asmlinkage void
|
|
|
+do_entDbg(struct pt_regs *regs)
|
|
|
+{
|
|
|
+ siginfo_t info;
|
|
|
+
|
|
|
+ die_if_kernel("Instruction fault", regs, 0, NULL);
|
|
|
+
|
|
|
+ info.si_signo = SIGILL;
|
|
|
+ info.si_errno = 0;
|
|
|
+ info.si_code = ILL_ILLOPC;
|
|
|
+ info.si_addr = (void __user *) regs->pc;
|
|
|
+ force_sig_info(SIGILL, &info, current);
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * entUna has a different register layout to be reasonably simple. It
|
|
|
+ * needs access to all the integer registers (the kernel doesn't use
|
|
|
+ * fp-regs), and it needs to have them in order for simpler access.
|
|
|
+ *
|
|
|
+ * Due to the non-standard register layout (and because we don't want
|
|
|
+ * to handle floating-point regs), user-mode unaligned accesses are
|
|
|
+ * handled separately by do_entUnaUser below.
|
|
|
+ *
|
|
|
+ * Oh, btw, we don't handle the "gp" register correctly, but if we fault
|
|
|
+ * on a gp-register unaligned load/store, something is _very_ wrong
|
|
|
+ * in the kernel anyway..
|
|
|
+ */
|
|
|
+struct allregs {
|
|
|
+ unsigned long regs[32];
|
|
|
+ unsigned long ps, pc, gp, a0, a1, a2;
|
|
|
+};
|
|
|
+
|
|
|
+struct unaligned_stat {
|
|
|
+ unsigned long count, va, pc;
|
|
|
+} unaligned[2];
|
|
|
+
|
|
|
+
|
|
|
+/* Macro for exception fixup code to access integer registers. */
|
|
|
+#define una_reg(r) (_regs[(r) >= 16 && (r) <= 18 ? (r)+19 : (r)])
|
|
|
+
|
|
|
+
|
|
|
+asmlinkage void
|
|
|
+do_entUna(void * va, unsigned long opcode, unsigned long reg,
|
|
|
+ struct allregs *regs)
|
|
|
+{
|
|
|
+ long error, tmp1, tmp2, tmp3, tmp4;
|
|
|
+ unsigned long pc = regs->pc - 4;
|
|
|
+ unsigned long *_regs = regs->regs;
|
|
|
+ const struct exception_table_entry *fixup;
|