#ifdef _KERNEL_OPT
#include "opt_cputype.h"
#endif
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <sys/signal.h>
#include <sys/siginfo.h>
#include <mips/cpuregs.h>
#include <mips/regnum.h>
#include <mips/locore.h>
#if defined(FPEMUL) || !defined(NOFPU)
void mips_fpuexcept(struct lwp *, uint32_t);
void mips_fpuillinst(struct lwp *, uint32_t);
static int fpustat2sicode(uint32_t);
void
mips_fpuexcept(struct lwp *l, uint32_t fpustat)
{
ksiginfo_t ksi;
#ifdef FPEMUL_DEBUG
printf("%s(%#x,%#"PRIxREGISTER")\n",
__func__, fpustat, l->l_md.md_utf->tf_regs[_R_PC]);
#endif
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGFPE;
ksi.ksi_code = fpustat2sicode(fpustat);
ksi.ksi_trap = fpustat;
(*l->l_proc->p_emul->e_trapsignal)(l, &ksi);
}
void
mips_fpuillinst(struct lwp *l, uint32_t opcode)
{
ksiginfo_t ksi;
#ifdef FPEMUL_DEBUG
printf("%s(%#x,%#"PRIxREGISTER")\n",
__func__, opcode, l->l_md.md_utf->tf_regs[_R_PC]);
#endif
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGILL;
ksi.ksi_code = ILL_ILLOPC;
ksi.ksi_trap = opcode;
ksi.ksi_addr = (void *)(uintptr_t)l->l_md.md_utf->tf_regs[_R_PC];
(*l->l_proc->p_emul->e_trapsignal)(l, &ksi);
}
static const struct {
unsigned int bit;
int code;
} fpecodes[] = {
{ MIPS_FCSR_CAUSE_I, FPE_FLTRES },
{ MIPS_FCSR_CAUSE_U, FPE_FLTUND },
{ MIPS_FCSR_CAUSE_O, FPE_FLTOVF },
{ MIPS_FCSR_CAUSE_Z, FPE_FLTDIV },
{ MIPS_FCSR_CAUSE_V, FPE_FLTINV },
{ MIPS_FCSR_CAUSE_E, FPE_FLTINV }
};
static int
fpustat2sicode(uint32_t fpustat)
{
for (size_t i = 0; i < __arraycount(fpecodes); i++) {
if (fpustat & fpecodes[i].bit)
return fpecodes[i].code;
}
return FPE_FLTINV;
}
#endif