36 #include <linux/sched.h>
37 #include <linux/module.h>
39 #include <linux/perf_event.h>
42 #include <asm/bootinfo.h>
43 #include <asm/processor.h>
44 #include <asm/ptrace.h>
45 #include <asm/signal.h>
48 #include <asm/uaccess.h>
65 #if __mips >= 4 && __mips != 32
66 static int fpux_emu(
struct pt_regs *,
72 #ifdef CONFIG_DEBUG_FS
82 #define modeindex(v) ((v) & FPU_CSR_RM)
85 static const unsigned char ieee_rm[4] = {
92 static const unsigned char mips_rm[4] = {
101 static const unsigned int fpucondbit[8] = {
179 static inline int cop1_64bit(
struct pt_regs *xcp)
184 return !test_thread_flag(TIF_32BIT_REGS);
190 #define SIFROMREG(si, x) ((si) = cop1_64bit(xcp) || !(x & 1) ? \
191 (int)ctx->fpr[x] : (int)(ctx->fpr[x & ~1] >> 32))
193 #define SITOREG(si, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = \
194 cop1_64bit(xcp) || !(x & 1) ? \
195 ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \
196 ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32)
198 #define DIFROMREG(di, x) ((di) = ctx->fpr[x & ~(cop1_64bit(xcp) == 0)])
199 #define DITOREG(di, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = (di))
201 #define SPFROMREG(sp, x) SIFROMREG((sp).bits, x)
202 #define SPTOREG(sp, x) SITOREG((sp).bits, x)
203 #define DPFROMREG(dp, x) DIFROMREG((dp).bits, x)
204 #define DPTOREG(dp, x) DITOREG((dp).bits, x)
212 void *__user *fault_addr)
215 unsigned long emulpc, contpc;
250 printk(
"failed to emulate branch at %p\n",
362 #if defined(__mips64)
399 printk(
"%p gpr[%d]<-csr=%08x\n",
426 printk(
"%p gpr[%d]->csr=%08x\n",
435 ctx->
fcr31 = (value &
496 #if (__mips >= 2 || defined(__mips64))
501 #if __mips >= 4 && __mips != 32
545 if ((sig = fpu_emu(xcp, ctx, ir)))
551 #if __mips >= 4 && __mips != 32
553 int sig = fpux_emu(xcp, ctx, ir, fault_addr);
586 static const unsigned char cmptab[8] = {
598 #if __mips >= 4 && __mips != 32
604 #define DEF3OP(name, p, f1, f2, f3) \
605 static ieee754##p fpemu_##p##_##name(ieee754##p r, ieee754##p s, \
608 struct _ieee754_csr ieee754_csr_save; \
610 ieee754_csr_save = ieee754_csr; \
612 ieee754_csr_save.cx |= ieee754_csr.cx; \
613 ieee754_csr_save.sx |= ieee754_csr.sx; \
615 ieee754_csr.cx |= ieee754_csr_save.cx; \
616 ieee754_csr.sx |= ieee754_csr_save.sx; \
620 static ieee754dp fpemu_dp_recip(ieee754dp
d)
625 static ieee754dp fpemu_dp_rsqrt(ieee754dp
d)
630 static ieee754sp fpemu_sp_recip(ieee754sp
s)
635 static ieee754sp fpemu_sp_rsqrt(ieee754sp s)
659 ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
719 fd = (*handler) (fr,
fs,
ft);
748 ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);
807 fd = (*handler) (fr,
fs,
ft);
856 ieee754sp(*
b) (ieee754sp, ieee754sp);
857 ieee754sp(*
u) (ieee754sp);
876 #if __mips >= 2 || defined(__mips64)
881 #if __mips >= 4 && __mips != 32
892 if (((ctx->
fcr31 & cond) != 0) !=
971 #if __mips >= 2 || defined(__mips64)
988 #if defined(__mips64)
1022 cmptab[cmpop & 0x7], cmpop & 0x8);
1024 if ((cmpop & 0x8) && ieee754_cxtest
1041 ieee754dp(*
b) (ieee754dp, ieee754dp);
1042 ieee754dp(*
u) (ieee754dp);
1061 #if __mips >= 2 || defined(__mips64)
1066 #if __mips >= 4 && __mips != 32
1077 if (((ctx->
fcr31 & cond) != 0) !=
1145 #if __mips >= 2 || defined(__mips64)
1162 #if defined(__mips64)
1196 cmptab[cmpop & 0x7], cmpop & 0x8);
1237 #if defined(__mips64)
1287 ctx->
fcr31 &= ~cond;
1299 #if defined(__mips64)
1312 int has_fpu,
void *__user *fault_addr)
1314 unsigned long oldepc, prevepc;
1343 sig = cop1Emulate(xcp, ctx, fault_addr);
1354 }
while (xcp->
cp0_epc > prevepc);
1364 #ifdef CONFIG_DEBUG_FS
1366 static int fpuemu_stat_get(
void *
data,
u64 *val)
1369 unsigned long sum = 0;
1371 struct mips_fpu_emulator_stats *
ps;
1373 ps = &
per_cpu(fpuemustats, cpu);
1374 pv = (
void *)ps + (
unsigned long)
data;
1383 static int __init debugfs_fpuemu(
void)
1387 if (!mips_debugfs_dir)
1393 #define FPU_STAT_CREATE(M) \
1395 d = debugfs_create_file(#M , S_IRUGO, dir, \
1396 (void *)offsetof(struct mips_fpu_emulator_stats, M), \
1397 &fops_fpuemu_stat); \
1402 FPU_STAT_CREATE(emulated);
1403 FPU_STAT_CREATE(loads);
1404 FPU_STAT_CREATE(stores);
1405 FPU_STAT_CREATE(cp1ops);
1406 FPU_STAT_CREATE(cp1xops);