Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/mips/math-emu/cp1emu.c
10817 views
1
/*
2
* cp1emu.c: a MIPS coprocessor 1 (fpu) instruction emulator
3
*
4
* MIPS floating point support
5
* Copyright (C) 1994-2000 Algorithmics Ltd.
6
*
7
* Kevin D. Kissell, [email protected] and Carsten Langgaard, [email protected]
8
* Copyright (C) 2000 MIPS Technologies, Inc.
9
*
10
* This program is free software; you can distribute it and/or modify it
11
* under the terms of the GNU General Public License (Version 2) as
12
* published by the Free Software Foundation.
13
*
14
* This program is distributed in the hope it will be useful, but WITHOUT
15
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17
* for more details.
18
*
19
* You should have received a copy of the GNU General Public License along
20
* with this program; if not, write to the Free Software Foundation, Inc.,
21
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
22
*
23
* A complete emulator for MIPS coprocessor 1 instructions. This is
24
* required for #float(switch) or #float(trap), where it catches all
25
* COP1 instructions via the "CoProcessor Unusable" exception.
26
*
27
* More surprisingly it is also required for #float(ieee), to help out
28
* the hardware fpu at the boundaries of the IEEE-754 representation
29
* (denormalised values, infinities, underflow, etc). It is made
30
* quite nasty because emulation of some non-COP1 instructions is
31
* required, e.g. in branch delay slots.
32
*
33
* Note if you know that you won't have an fpu, then you'll get much
34
* better performance by compiling with -msoft-float!
35
*/
36
#include <linux/sched.h>
37
#include <linux/module.h>
38
#include <linux/debugfs.h>
39
#include <linux/perf_event.h>
40
41
#include <asm/inst.h>
42
#include <asm/bootinfo.h>
43
#include <asm/processor.h>
44
#include <asm/ptrace.h>
45
#include <asm/signal.h>
46
#include <asm/mipsregs.h>
47
#include <asm/fpu_emulator.h>
48
#include <asm/uaccess.h>
49
#include <asm/branch.h>
50
51
#include "ieee754.h"
52
53
/* Strap kernel emulator for full MIPS IV emulation */
54
55
#ifdef __mips
56
#undef __mips
57
#endif
58
#define __mips 4
59
60
/* Function which emulates a floating point instruction. */
61
62
static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *,
63
mips_instruction);
64
65
#if __mips >= 4 && __mips != 32
66
static int fpux_emu(struct pt_regs *,
67
struct mips_fpu_struct *, mips_instruction, void *__user *);
68
#endif
69
70
/* Further private data for which no space exists in mips_fpu_struct */
71
72
#ifdef CONFIG_DEBUG_FS
73
DEFINE_PER_CPU(struct mips_fpu_emulator_stats, fpuemustats);
74
#endif
75
76
/* Control registers */
77
78
#define FPCREG_RID 0 /* $0 = revision id */
79
#define FPCREG_CSR 31 /* $31 = csr */
80
81
/* Determine rounding mode from the RM bits of the FCSR */
82
#define modeindex(v) ((v) & FPU_CSR_RM)
83
84
/* Convert Mips rounding mode (0..3) to IEEE library modes. */
85
static const unsigned char ieee_rm[4] = {
86
[FPU_CSR_RN] = IEEE754_RN,
87
[FPU_CSR_RZ] = IEEE754_RZ,
88
[FPU_CSR_RU] = IEEE754_RU,
89
[FPU_CSR_RD] = IEEE754_RD,
90
};
91
/* Convert IEEE library modes to Mips rounding mode (0..3). */
92
static const unsigned char mips_rm[4] = {
93
[IEEE754_RN] = FPU_CSR_RN,
94
[IEEE754_RZ] = FPU_CSR_RZ,
95
[IEEE754_RD] = FPU_CSR_RD,
96
[IEEE754_RU] = FPU_CSR_RU,
97
};
98
99
#if __mips >= 4
100
/* convert condition code register number to csr bit */
101
static const unsigned int fpucondbit[8] = {
102
FPU_CSR_COND0,
103
FPU_CSR_COND1,
104
FPU_CSR_COND2,
105
FPU_CSR_COND3,
106
FPU_CSR_COND4,
107
FPU_CSR_COND5,
108
FPU_CSR_COND6,
109
FPU_CSR_COND7
110
};
111
#endif
112
113
114
/*
115
* Redundant with logic already in kernel/branch.c,
116
* embedded in compute_return_epc. At some point,
117
* a single subroutine should be used across both
118
* modules.
119
*/
120
static int isBranchInstr(mips_instruction * i)
121
{
122
switch (MIPSInst_OPCODE(*i)) {
123
case spec_op:
124
switch (MIPSInst_FUNC(*i)) {
125
case jalr_op:
126
case jr_op:
127
return 1;
128
}
129
break;
130
131
case bcond_op:
132
switch (MIPSInst_RT(*i)) {
133
case bltz_op:
134
case bgez_op:
135
case bltzl_op:
136
case bgezl_op:
137
case bltzal_op:
138
case bgezal_op:
139
case bltzall_op:
140
case bgezall_op:
141
return 1;
142
}
143
break;
144
145
case j_op:
146
case jal_op:
147
case jalx_op:
148
case beq_op:
149
case bne_op:
150
case blez_op:
151
case bgtz_op:
152
case beql_op:
153
case bnel_op:
154
case blezl_op:
155
case bgtzl_op:
156
return 1;
157
158
case cop0_op:
159
case cop1_op:
160
case cop2_op:
161
case cop1x_op:
162
if (MIPSInst_RS(*i) == bc_op)
163
return 1;
164
break;
165
}
166
167
return 0;
168
}
169
170
/*
171
* In the Linux kernel, we support selection of FPR format on the
172
* basis of the Status.FR bit. If an FPU is not present, the FR bit
173
* is hardwired to zero, which would imply a 32-bit FPU even for
174
* 64-bit CPUs. For 64-bit kernels with no FPU we use TIF_32BIT_REGS
175
* as a proxy for the FR bit so that a 64-bit FPU is emulated. In any
176
* case, for a 32-bit kernel which uses the O32 MIPS ABI, only the
177
* even FPRs are used (Status.FR = 0).
178
*/
179
static inline int cop1_64bit(struct pt_regs *xcp)
180
{
181
if (cpu_has_fpu)
182
return xcp->cp0_status & ST0_FR;
183
#ifdef CONFIG_64BIT
184
return !test_thread_flag(TIF_32BIT_REGS);
185
#else
186
return 0;
187
#endif
188
}
189
190
#define SIFROMREG(si, x) ((si) = cop1_64bit(xcp) || !(x & 1) ? \
191
(int)ctx->fpr[x] : (int)(ctx->fpr[x & ~1] >> 32))
192
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)
197
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))
200
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)
205
206
/*
207
* Emulate the single floating point instruction pointed at by EPC.
208
* Two instructions if the instruction is in a branch delay slot.
209
*/
210
211
static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
212
void *__user *fault_addr)
213
{
214
mips_instruction ir;
215
unsigned long emulpc, contpc;
216
unsigned int cond;
217
218
if (!access_ok(VERIFY_READ, xcp->cp0_epc, sizeof(mips_instruction))) {
219
MIPS_FPU_EMU_INC_STATS(errors);
220
*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
221
return SIGBUS;
222
}
223
if (__get_user(ir, (mips_instruction __user *) xcp->cp0_epc)) {
224
MIPS_FPU_EMU_INC_STATS(errors);
225
*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
226
return SIGSEGV;
227
}
228
229
/* XXX NEC Vr54xx bug workaround */
230
if ((xcp->cp0_cause & CAUSEF_BD) && !isBranchInstr(&ir))
231
xcp->cp0_cause &= ~CAUSEF_BD;
232
233
if (xcp->cp0_cause & CAUSEF_BD) {
234
/*
235
* The instruction to be emulated is in a branch delay slot
236
* which means that we have to emulate the branch instruction
237
* BEFORE we do the cop1 instruction.
238
*
239
* This branch could be a COP1 branch, but in that case we
240
* would have had a trap for that instruction, and would not
241
* come through this route.
242
*
243
* Linux MIPS branch emulator operates on context, updating the
244
* cp0_epc.
245
*/
246
emulpc = xcp->cp0_epc + 4; /* Snapshot emulation target */
247
248
if (__compute_return_epc(xcp)) {
249
#ifdef CP1DBG
250
printk("failed to emulate branch at %p\n",
251
(void *) (xcp->cp0_epc));
252
#endif
253
return SIGILL;
254
}
255
if (!access_ok(VERIFY_READ, emulpc, sizeof(mips_instruction))) {
256
MIPS_FPU_EMU_INC_STATS(errors);
257
*fault_addr = (mips_instruction __user *)emulpc;
258
return SIGBUS;
259
}
260
if (__get_user(ir, (mips_instruction __user *) emulpc)) {
261
MIPS_FPU_EMU_INC_STATS(errors);
262
*fault_addr = (mips_instruction __user *)emulpc;
263
return SIGSEGV;
264
}
265
/* __compute_return_epc() will have updated cp0_epc */
266
contpc = xcp->cp0_epc;
267
/* In order not to confuse ptrace() et al, tweak context */
268
xcp->cp0_epc = emulpc - 4;
269
} else {
270
emulpc = xcp->cp0_epc;
271
contpc = xcp->cp0_epc + 4;
272
}
273
274
emul:
275
perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS,
276
1, 0, xcp, 0);
277
MIPS_FPU_EMU_INC_STATS(emulated);
278
switch (MIPSInst_OPCODE(ir)) {
279
case ldc1_op:{
280
u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] +
281
MIPSInst_SIMM(ir));
282
u64 val;
283
284
MIPS_FPU_EMU_INC_STATS(loads);
285
286
if (!access_ok(VERIFY_READ, va, sizeof(u64))) {
287
MIPS_FPU_EMU_INC_STATS(errors);
288
*fault_addr = va;
289
return SIGBUS;
290
}
291
if (__get_user(val, va)) {
292
MIPS_FPU_EMU_INC_STATS(errors);
293
*fault_addr = va;
294
return SIGSEGV;
295
}
296
DITOREG(val, MIPSInst_RT(ir));
297
break;
298
}
299
300
case sdc1_op:{
301
u64 __user *va = (u64 __user *) (xcp->regs[MIPSInst_RS(ir)] +
302
MIPSInst_SIMM(ir));
303
u64 val;
304
305
MIPS_FPU_EMU_INC_STATS(stores);
306
DIFROMREG(val, MIPSInst_RT(ir));
307
if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) {
308
MIPS_FPU_EMU_INC_STATS(errors);
309
*fault_addr = va;
310
return SIGBUS;
311
}
312
if (__put_user(val, va)) {
313
MIPS_FPU_EMU_INC_STATS(errors);
314
*fault_addr = va;
315
return SIGSEGV;
316
}
317
break;
318
}
319
320
case lwc1_op:{
321
u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] +
322
MIPSInst_SIMM(ir));
323
u32 val;
324
325
MIPS_FPU_EMU_INC_STATS(loads);
326
if (!access_ok(VERIFY_READ, va, sizeof(u32))) {
327
MIPS_FPU_EMU_INC_STATS(errors);
328
*fault_addr = va;
329
return SIGBUS;
330
}
331
if (__get_user(val, va)) {
332
MIPS_FPU_EMU_INC_STATS(errors);
333
*fault_addr = va;
334
return SIGSEGV;
335
}
336
SITOREG(val, MIPSInst_RT(ir));
337
break;
338
}
339
340
case swc1_op:{
341
u32 __user *va = (u32 __user *) (xcp->regs[MIPSInst_RS(ir)] +
342
MIPSInst_SIMM(ir));
343
u32 val;
344
345
MIPS_FPU_EMU_INC_STATS(stores);
346
SIFROMREG(val, MIPSInst_RT(ir));
347
if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) {
348
MIPS_FPU_EMU_INC_STATS(errors);
349
*fault_addr = va;
350
return SIGBUS;
351
}
352
if (__put_user(val, va)) {
353
MIPS_FPU_EMU_INC_STATS(errors);
354
*fault_addr = va;
355
return SIGSEGV;
356
}
357
break;
358
}
359
360
case cop1_op:
361
switch (MIPSInst_RS(ir)) {
362
363
#if defined(__mips64)
364
case dmfc_op:
365
/* copregister fs -> gpr[rt] */
366
if (MIPSInst_RT(ir) != 0) {
367
DIFROMREG(xcp->regs[MIPSInst_RT(ir)],
368
MIPSInst_RD(ir));
369
}
370
break;
371
372
case dmtc_op:
373
/* copregister fs <- rt */
374
DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
375
break;
376
#endif
377
378
case mfc_op:
379
/* copregister rd -> gpr[rt] */
380
if (MIPSInst_RT(ir) != 0) {
381
SIFROMREG(xcp->regs[MIPSInst_RT(ir)],
382
MIPSInst_RD(ir));
383
}
384
break;
385
386
case mtc_op:
387
/* copregister rd <- rt */
388
SITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
389
break;
390
391
case cfc_op:{
392
/* cop control register rd -> gpr[rt] */
393
u32 value;
394
395
if (MIPSInst_RD(ir) == FPCREG_CSR) {
396
value = ctx->fcr31;
397
value = (value & ~FPU_CSR_RM) |
398
mips_rm[modeindex(value)];
399
#ifdef CSRTRACE
400
printk("%p gpr[%d]<-csr=%08x\n",
401
(void *) (xcp->cp0_epc),
402
MIPSInst_RT(ir), value);
403
#endif
404
}
405
else if (MIPSInst_RD(ir) == FPCREG_RID)
406
value = 0;
407
else
408
value = 0;
409
if (MIPSInst_RT(ir))
410
xcp->regs[MIPSInst_RT(ir)] = value;
411
break;
412
}
413
414
case ctc_op:{
415
/* copregister rd <- rt */
416
u32 value;
417
418
if (MIPSInst_RT(ir) == 0)
419
value = 0;
420
else
421
value = xcp->regs[MIPSInst_RT(ir)];
422
423
/* we only have one writable control reg
424
*/
425
if (MIPSInst_RD(ir) == FPCREG_CSR) {
426
#ifdef CSRTRACE
427
printk("%p gpr[%d]->csr=%08x\n",
428
(void *) (xcp->cp0_epc),
429
MIPSInst_RT(ir), value);
430
#endif
431
432
/*
433
* Don't write reserved bits,
434
* and convert to ieee library modes
435
*/
436
ctx->fcr31 = (value &
437
~(FPU_CSR_RSVD | FPU_CSR_RM)) |
438
ieee_rm[modeindex(value)];
439
}
440
if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
441
return SIGFPE;
442
}
443
break;
444
}
445
446
case bc_op:{
447
int likely = 0;
448
449
if (xcp->cp0_cause & CAUSEF_BD)
450
return SIGILL;
451
452
#if __mips >= 4
453
cond = ctx->fcr31 & fpucondbit[MIPSInst_RT(ir) >> 2];
454
#else
455
cond = ctx->fcr31 & FPU_CSR_COND;
456
#endif
457
switch (MIPSInst_RT(ir) & 3) {
458
case bcfl_op:
459
likely = 1;
460
case bcf_op:
461
cond = !cond;
462
break;
463
case bctl_op:
464
likely = 1;
465
case bct_op:
466
break;
467
default:
468
/* thats an illegal instruction */
469
return SIGILL;
470
}
471
472
xcp->cp0_cause |= CAUSEF_BD;
473
if (cond) {
474
/* branch taken: emulate dslot
475
* instruction
476
*/
477
xcp->cp0_epc += 4;
478
contpc = (xcp->cp0_epc +
479
(MIPSInst_SIMM(ir) << 2));
480
481
if (!access_ok(VERIFY_READ, xcp->cp0_epc,
482
sizeof(mips_instruction))) {
483
MIPS_FPU_EMU_INC_STATS(errors);
484
*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
485
return SIGBUS;
486
}
487
if (__get_user(ir,
488
(mips_instruction __user *) xcp->cp0_epc)) {
489
MIPS_FPU_EMU_INC_STATS(errors);
490
*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
491
return SIGSEGV;
492
}
493
494
switch (MIPSInst_OPCODE(ir)) {
495
case lwc1_op:
496
case swc1_op:
497
#if (__mips >= 2 || defined(__mips64))
498
case ldc1_op:
499
case sdc1_op:
500
#endif
501
case cop1_op:
502
#if __mips >= 4 && __mips != 32
503
case cop1x_op:
504
#endif
505
/* its one of ours */
506
goto emul;
507
#if __mips >= 4
508
case spec_op:
509
if (MIPSInst_FUNC(ir) == movc_op)
510
goto emul;
511
break;
512
#endif
513
}
514
515
/*
516
* Single step the non-cp1
517
* instruction in the dslot
518
*/
519
return mips_dsemul(xcp, ir, contpc);
520
}
521
else {
522
/* branch not taken */
523
if (likely) {
524
/*
525
* branch likely nullifies
526
* dslot if not taken
527
*/
528
xcp->cp0_epc += 4;
529
contpc += 4;
530
/*
531
* else continue & execute
532
* dslot as normal insn
533
*/
534
}
535
}
536
break;
537
}
538
539
default:
540
if (!(MIPSInst_RS(ir) & 0x10))
541
return SIGILL;
542
{
543
int sig;
544
545
/* a real fpu computation instruction */
546
if ((sig = fpu_emu(xcp, ctx, ir)))
547
return sig;
548
}
549
}
550
break;
551
552
#if __mips >= 4 && __mips != 32
553
case cop1x_op:{
554
int sig = fpux_emu(xcp, ctx, ir, fault_addr);
555
if (sig)
556
return sig;
557
break;
558
}
559
#endif
560
561
#if __mips >= 4
562
case spec_op:
563
if (MIPSInst_FUNC(ir) != movc_op)
564
return SIGILL;
565
cond = fpucondbit[MIPSInst_RT(ir) >> 2];
566
if (((ctx->fcr31 & cond) != 0) == ((MIPSInst_RT(ir) & 1) != 0))
567
xcp->regs[MIPSInst_RD(ir)] =
568
xcp->regs[MIPSInst_RS(ir)];
569
break;
570
#endif
571
572
default:
573
return SIGILL;
574
}
575
576
/* we did it !! */
577
xcp->cp0_epc = contpc;
578
xcp->cp0_cause &= ~CAUSEF_BD;
579
580
return 0;
581
}
582
583
/*
584
* Conversion table from MIPS compare ops 48-63
585
* cond = ieee754dp_cmp(x,y,IEEE754_UN,sig);
586
*/
587
static const unsigned char cmptab[8] = {
588
0, /* cmp_0 (sig) cmp_sf */
589
IEEE754_CUN, /* cmp_un (sig) cmp_ngle */
590
IEEE754_CEQ, /* cmp_eq (sig) cmp_seq */
591
IEEE754_CEQ | IEEE754_CUN, /* cmp_ueq (sig) cmp_ngl */
592
IEEE754_CLT, /* cmp_olt (sig) cmp_lt */
593
IEEE754_CLT | IEEE754_CUN, /* cmp_ult (sig) cmp_nge */
594
IEEE754_CLT | IEEE754_CEQ, /* cmp_ole (sig) cmp_le */
595
IEEE754_CLT | IEEE754_CEQ | IEEE754_CUN, /* cmp_ule (sig) cmp_ngt */
596
};
597
598
599
#if __mips >= 4 && __mips != 32
600
601
/*
602
* Additional MIPS4 instructions
603
*/
604
605
#define DEF3OP(name, p, f1, f2, f3) \
606
static ieee754##p fpemu_##p##_##name(ieee754##p r, ieee754##p s, \
607
ieee754##p t) \
608
{ \
609
struct _ieee754_csr ieee754_csr_save; \
610
s = f1(s, t); \
611
ieee754_csr_save = ieee754_csr; \
612
s = f2(s, r); \
613
ieee754_csr_save.cx |= ieee754_csr.cx; \
614
ieee754_csr_save.sx |= ieee754_csr.sx; \
615
s = f3(s); \
616
ieee754_csr.cx |= ieee754_csr_save.cx; \
617
ieee754_csr.sx |= ieee754_csr_save.sx; \
618
return s; \
619
}
620
621
static ieee754dp fpemu_dp_recip(ieee754dp d)
622
{
623
return ieee754dp_div(ieee754dp_one(0), d);
624
}
625
626
static ieee754dp fpemu_dp_rsqrt(ieee754dp d)
627
{
628
return ieee754dp_div(ieee754dp_one(0), ieee754dp_sqrt(d));
629
}
630
631
static ieee754sp fpemu_sp_recip(ieee754sp s)
632
{
633
return ieee754sp_div(ieee754sp_one(0), s);
634
}
635
636
static ieee754sp fpemu_sp_rsqrt(ieee754sp s)
637
{
638
return ieee754sp_div(ieee754sp_one(0), ieee754sp_sqrt(s));
639
}
640
641
DEF3OP(madd, sp, ieee754sp_mul, ieee754sp_add, );
642
DEF3OP(msub, sp, ieee754sp_mul, ieee754sp_sub, );
643
DEF3OP(nmadd, sp, ieee754sp_mul, ieee754sp_add, ieee754sp_neg);
644
DEF3OP(nmsub, sp, ieee754sp_mul, ieee754sp_sub, ieee754sp_neg);
645
DEF3OP(madd, dp, ieee754dp_mul, ieee754dp_add, );
646
DEF3OP(msub, dp, ieee754dp_mul, ieee754dp_sub, );
647
DEF3OP(nmadd, dp, ieee754dp_mul, ieee754dp_add, ieee754dp_neg);
648
DEF3OP(nmsub, dp, ieee754dp_mul, ieee754dp_sub, ieee754dp_neg);
649
650
static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
651
mips_instruction ir, void *__user *fault_addr)
652
{
653
unsigned rcsr = 0; /* resulting csr */
654
655
MIPS_FPU_EMU_INC_STATS(cp1xops);
656
657
switch (MIPSInst_FMA_FFMT(ir)) {
658
case s_fmt:{ /* 0 */
659
660
ieee754sp(*handler) (ieee754sp, ieee754sp, ieee754sp);
661
ieee754sp fd, fr, fs, ft;
662
u32 __user *va;
663
u32 val;
664
665
switch (MIPSInst_FUNC(ir)) {
666
case lwxc1_op:
667
va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] +
668
xcp->regs[MIPSInst_FT(ir)]);
669
670
MIPS_FPU_EMU_INC_STATS(loads);
671
if (!access_ok(VERIFY_READ, va, sizeof(u32))) {
672
MIPS_FPU_EMU_INC_STATS(errors);
673
*fault_addr = va;
674
return SIGBUS;
675
}
676
if (__get_user(val, va)) {
677
MIPS_FPU_EMU_INC_STATS(errors);
678
*fault_addr = va;
679
return SIGSEGV;
680
}
681
SITOREG(val, MIPSInst_FD(ir));
682
break;
683
684
case swxc1_op:
685
va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] +
686
xcp->regs[MIPSInst_FT(ir)]);
687
688
MIPS_FPU_EMU_INC_STATS(stores);
689
690
SIFROMREG(val, MIPSInst_FS(ir));
691
if (!access_ok(VERIFY_WRITE, va, sizeof(u32))) {
692
MIPS_FPU_EMU_INC_STATS(errors);
693
*fault_addr = va;
694
return SIGBUS;
695
}
696
if (put_user(val, va)) {
697
MIPS_FPU_EMU_INC_STATS(errors);
698
*fault_addr = va;
699
return SIGSEGV;
700
}
701
break;
702
703
case madd_s_op:
704
handler = fpemu_sp_madd;
705
goto scoptop;
706
case msub_s_op:
707
handler = fpemu_sp_msub;
708
goto scoptop;
709
case nmadd_s_op:
710
handler = fpemu_sp_nmadd;
711
goto scoptop;
712
case nmsub_s_op:
713
handler = fpemu_sp_nmsub;
714
goto scoptop;
715
716
scoptop:
717
SPFROMREG(fr, MIPSInst_FR(ir));
718
SPFROMREG(fs, MIPSInst_FS(ir));
719
SPFROMREG(ft, MIPSInst_FT(ir));
720
fd = (*handler) (fr, fs, ft);
721
SPTOREG(fd, MIPSInst_FD(ir));
722
723
copcsr:
724
if (ieee754_cxtest(IEEE754_INEXACT))
725
rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
726
if (ieee754_cxtest(IEEE754_UNDERFLOW))
727
rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
728
if (ieee754_cxtest(IEEE754_OVERFLOW))
729
rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
730
if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
731
rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
732
733
ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
734
if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
735
/*printk ("SIGFPE: fpu csr = %08x\n",
736
ctx->fcr31); */
737
return SIGFPE;
738
}
739
740
break;
741
742
default:
743
return SIGILL;
744
}
745
break;
746
}
747
748
case d_fmt:{ /* 1 */
749
ieee754dp(*handler) (ieee754dp, ieee754dp, ieee754dp);
750
ieee754dp fd, fr, fs, ft;
751
u64 __user *va;
752
u64 val;
753
754
switch (MIPSInst_FUNC(ir)) {
755
case ldxc1_op:
756
va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] +
757
xcp->regs[MIPSInst_FT(ir)]);
758
759
MIPS_FPU_EMU_INC_STATS(loads);
760
if (!access_ok(VERIFY_READ, va, sizeof(u64))) {
761
MIPS_FPU_EMU_INC_STATS(errors);
762
*fault_addr = va;
763
return SIGBUS;
764
}
765
if (__get_user(val, va)) {
766
MIPS_FPU_EMU_INC_STATS(errors);
767
*fault_addr = va;
768
return SIGSEGV;
769
}
770
DITOREG(val, MIPSInst_FD(ir));
771
break;
772
773
case sdxc1_op:
774
va = (void __user *) (xcp->regs[MIPSInst_FR(ir)] +
775
xcp->regs[MIPSInst_FT(ir)]);
776
777
MIPS_FPU_EMU_INC_STATS(stores);
778
DIFROMREG(val, MIPSInst_FS(ir));
779
if (!access_ok(VERIFY_WRITE, va, sizeof(u64))) {
780
MIPS_FPU_EMU_INC_STATS(errors);
781
*fault_addr = va;
782
return SIGBUS;
783
}
784
if (__put_user(val, va)) {
785
MIPS_FPU_EMU_INC_STATS(errors);
786
*fault_addr = va;
787
return SIGSEGV;
788
}
789
break;
790
791
case madd_d_op:
792
handler = fpemu_dp_madd;
793
goto dcoptop;
794
case msub_d_op:
795
handler = fpemu_dp_msub;
796
goto dcoptop;
797
case nmadd_d_op:
798
handler = fpemu_dp_nmadd;
799
goto dcoptop;
800
case nmsub_d_op:
801
handler = fpemu_dp_nmsub;
802
goto dcoptop;
803
804
dcoptop:
805
DPFROMREG(fr, MIPSInst_FR(ir));
806
DPFROMREG(fs, MIPSInst_FS(ir));
807
DPFROMREG(ft, MIPSInst_FT(ir));
808
fd = (*handler) (fr, fs, ft);
809
DPTOREG(fd, MIPSInst_FD(ir));
810
goto copcsr;
811
812
default:
813
return SIGILL;
814
}
815
break;
816
}
817
818
case 0x7: /* 7 */
819
if (MIPSInst_FUNC(ir) != pfetch_op) {
820
return SIGILL;
821
}
822
/* ignore prefx operation */
823
break;
824
825
default:
826
return SIGILL;
827
}
828
829
return 0;
830
}
831
#endif
832
833
834
835
/*
836
* Emulate a single COP1 arithmetic instruction.
837
*/
838
static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
839
mips_instruction ir)
840
{
841
int rfmt; /* resulting format */
842
unsigned rcsr = 0; /* resulting csr */
843
unsigned cond;
844
union {
845
ieee754dp d;
846
ieee754sp s;
847
int w;
848
#ifdef __mips64
849
s64 l;
850
#endif
851
} rv; /* resulting value */
852
853
MIPS_FPU_EMU_INC_STATS(cp1ops);
854
switch (rfmt = (MIPSInst_FFMT(ir) & 0xf)) {
855
case s_fmt:{ /* 0 */
856
union {
857
ieee754sp(*b) (ieee754sp, ieee754sp);
858
ieee754sp(*u) (ieee754sp);
859
} handler;
860
861
switch (MIPSInst_FUNC(ir)) {
862
/* binary ops */
863
case fadd_op:
864
handler.b = ieee754sp_add;
865
goto scopbop;
866
case fsub_op:
867
handler.b = ieee754sp_sub;
868
goto scopbop;
869
case fmul_op:
870
handler.b = ieee754sp_mul;
871
goto scopbop;
872
case fdiv_op:
873
handler.b = ieee754sp_div;
874
goto scopbop;
875
876
/* unary ops */
877
#if __mips >= 2 || defined(__mips64)
878
case fsqrt_op:
879
handler.u = ieee754sp_sqrt;
880
goto scopuop;
881
#endif
882
#if __mips >= 4 && __mips != 32
883
case frsqrt_op:
884
handler.u = fpemu_sp_rsqrt;
885
goto scopuop;
886
case frecip_op:
887
handler.u = fpemu_sp_recip;
888
goto scopuop;
889
#endif
890
#if __mips >= 4
891
case fmovc_op:
892
cond = fpucondbit[MIPSInst_FT(ir) >> 2];
893
if (((ctx->fcr31 & cond) != 0) !=
894
((MIPSInst_FT(ir) & 1) != 0))
895
return 0;
896
SPFROMREG(rv.s, MIPSInst_FS(ir));
897
break;
898
case fmovz_op:
899
if (xcp->regs[MIPSInst_FT(ir)] != 0)
900
return 0;
901
SPFROMREG(rv.s, MIPSInst_FS(ir));
902
break;
903
case fmovn_op:
904
if (xcp->regs[MIPSInst_FT(ir)] == 0)
905
return 0;
906
SPFROMREG(rv.s, MIPSInst_FS(ir));
907
break;
908
#endif
909
case fabs_op:
910
handler.u = ieee754sp_abs;
911
goto scopuop;
912
case fneg_op:
913
handler.u = ieee754sp_neg;
914
goto scopuop;
915
case fmov_op:
916
/* an easy one */
917
SPFROMREG(rv.s, MIPSInst_FS(ir));
918
goto copcsr;
919
920
/* binary op on handler */
921
scopbop:
922
{
923
ieee754sp fs, ft;
924
925
SPFROMREG(fs, MIPSInst_FS(ir));
926
SPFROMREG(ft, MIPSInst_FT(ir));
927
928
rv.s = (*handler.b) (fs, ft);
929
goto copcsr;
930
}
931
scopuop:
932
{
933
ieee754sp fs;
934
935
SPFROMREG(fs, MIPSInst_FS(ir));
936
rv.s = (*handler.u) (fs);
937
goto copcsr;
938
}
939
copcsr:
940
if (ieee754_cxtest(IEEE754_INEXACT))
941
rcsr |= FPU_CSR_INE_X | FPU_CSR_INE_S;
942
if (ieee754_cxtest(IEEE754_UNDERFLOW))
943
rcsr |= FPU_CSR_UDF_X | FPU_CSR_UDF_S;
944
if (ieee754_cxtest(IEEE754_OVERFLOW))
945
rcsr |= FPU_CSR_OVF_X | FPU_CSR_OVF_S;
946
if (ieee754_cxtest(IEEE754_ZERO_DIVIDE))
947
rcsr |= FPU_CSR_DIV_X | FPU_CSR_DIV_S;
948
if (ieee754_cxtest(IEEE754_INVALID_OPERATION))
949
rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;
950
break;
951
952
/* unary conv ops */
953
case fcvts_op:
954
return SIGILL; /* not defined */
955
case fcvtd_op:{
956
ieee754sp fs;
957
958
SPFROMREG(fs, MIPSInst_FS(ir));
959
rv.d = ieee754dp_fsp(fs);
960
rfmt = d_fmt;
961
goto copcsr;
962
}
963
case fcvtw_op:{
964
ieee754sp fs;
965
966
SPFROMREG(fs, MIPSInst_FS(ir));
967
rv.w = ieee754sp_tint(fs);
968
rfmt = w_fmt;
969
goto copcsr;
970
}
971
972
#if __mips >= 2 || defined(__mips64)
973
case fround_op:
974
case ftrunc_op:
975
case fceil_op:
976
case ffloor_op:{
977
unsigned int oldrm = ieee754_csr.rm;
978
ieee754sp fs;
979
980
SPFROMREG(fs, MIPSInst_FS(ir));
981
ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))];
982
rv.w = ieee754sp_tint(fs);
983
ieee754_csr.rm = oldrm;
984
rfmt = w_fmt;
985
goto copcsr;
986
}
987
#endif /* __mips >= 2 */
988
989
#if defined(__mips64)
990
case fcvtl_op:{
991
ieee754sp fs;
992
993
SPFROMREG(fs, MIPSInst_FS(ir));
994
rv.l = ieee754sp_tlong(fs);
995
rfmt = l_fmt;
996
goto copcsr;
997
}
998
999
case froundl_op:
1000
case ftruncl_op:
1001
case fceill_op:
1002
case ffloorl_op:{
1003
unsigned int oldrm = ieee754_csr.rm;
1004
ieee754sp fs;
1005
1006
SPFROMREG(fs, MIPSInst_FS(ir));
1007
ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))];
1008
rv.l = ieee754sp_tlong(fs);
1009
ieee754_csr.rm = oldrm;
1010
rfmt = l_fmt;
1011
goto copcsr;
1012
}
1013
#endif /* defined(__mips64) */
1014
1015
default:
1016
if (MIPSInst_FUNC(ir) >= fcmp_op) {
1017
unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
1018
ieee754sp fs, ft;
1019
1020
SPFROMREG(fs, MIPSInst_FS(ir));
1021
SPFROMREG(ft, MIPSInst_FT(ir));
1022
rv.w = ieee754sp_cmp(fs, ft,
1023
cmptab[cmpop & 0x7], cmpop & 0x8);
1024
rfmt = -1;
1025
if ((cmpop & 0x8) && ieee754_cxtest
1026
(IEEE754_INVALID_OPERATION))
1027
rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
1028
else
1029
goto copcsr;
1030
1031
}
1032
else {
1033
return SIGILL;
1034
}
1035
break;
1036
}
1037
break;
1038
}
1039
1040
case d_fmt:{
1041
union {
1042
ieee754dp(*b) (ieee754dp, ieee754dp);
1043
ieee754dp(*u) (ieee754dp);
1044
} handler;
1045
1046
switch (MIPSInst_FUNC(ir)) {
1047
/* binary ops */
1048
case fadd_op:
1049
handler.b = ieee754dp_add;
1050
goto dcopbop;
1051
case fsub_op:
1052
handler.b = ieee754dp_sub;
1053
goto dcopbop;
1054
case fmul_op:
1055
handler.b = ieee754dp_mul;
1056
goto dcopbop;
1057
case fdiv_op:
1058
handler.b = ieee754dp_div;
1059
goto dcopbop;
1060
1061
/* unary ops */
1062
#if __mips >= 2 || defined(__mips64)
1063
case fsqrt_op:
1064
handler.u = ieee754dp_sqrt;
1065
goto dcopuop;
1066
#endif
1067
#if __mips >= 4 && __mips != 32
1068
case frsqrt_op:
1069
handler.u = fpemu_dp_rsqrt;
1070
goto dcopuop;
1071
case frecip_op:
1072
handler.u = fpemu_dp_recip;
1073
goto dcopuop;
1074
#endif
1075
#if __mips >= 4
1076
case fmovc_op:
1077
cond = fpucondbit[MIPSInst_FT(ir) >> 2];
1078
if (((ctx->fcr31 & cond) != 0) !=
1079
((MIPSInst_FT(ir) & 1) != 0))
1080
return 0;
1081
DPFROMREG(rv.d, MIPSInst_FS(ir));
1082
break;
1083
case fmovz_op:
1084
if (xcp->regs[MIPSInst_FT(ir)] != 0)
1085
return 0;
1086
DPFROMREG(rv.d, MIPSInst_FS(ir));
1087
break;
1088
case fmovn_op:
1089
if (xcp->regs[MIPSInst_FT(ir)] == 0)
1090
return 0;
1091
DPFROMREG(rv.d, MIPSInst_FS(ir));
1092
break;
1093
#endif
1094
case fabs_op:
1095
handler.u = ieee754dp_abs;
1096
goto dcopuop;
1097
1098
case fneg_op:
1099
handler.u = ieee754dp_neg;
1100
goto dcopuop;
1101
1102
case fmov_op:
1103
/* an easy one */
1104
DPFROMREG(rv.d, MIPSInst_FS(ir));
1105
goto copcsr;
1106
1107
/* binary op on handler */
1108
dcopbop:{
1109
ieee754dp fs, ft;
1110
1111
DPFROMREG(fs, MIPSInst_FS(ir));
1112
DPFROMREG(ft, MIPSInst_FT(ir));
1113
1114
rv.d = (*handler.b) (fs, ft);
1115
goto copcsr;
1116
}
1117
dcopuop:{
1118
ieee754dp fs;
1119
1120
DPFROMREG(fs, MIPSInst_FS(ir));
1121
rv.d = (*handler.u) (fs);
1122
goto copcsr;
1123
}
1124
1125
/* unary conv ops */
1126
case fcvts_op:{
1127
ieee754dp fs;
1128
1129
DPFROMREG(fs, MIPSInst_FS(ir));
1130
rv.s = ieee754sp_fdp(fs);
1131
rfmt = s_fmt;
1132
goto copcsr;
1133
}
1134
case fcvtd_op:
1135
return SIGILL; /* not defined */
1136
1137
case fcvtw_op:{
1138
ieee754dp fs;
1139
1140
DPFROMREG(fs, MIPSInst_FS(ir));
1141
rv.w = ieee754dp_tint(fs); /* wrong */
1142
rfmt = w_fmt;
1143
goto copcsr;
1144
}
1145
1146
#if __mips >= 2 || defined(__mips64)
1147
case fround_op:
1148
case ftrunc_op:
1149
case fceil_op:
1150
case ffloor_op:{
1151
unsigned int oldrm = ieee754_csr.rm;
1152
ieee754dp fs;
1153
1154
DPFROMREG(fs, MIPSInst_FS(ir));
1155
ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))];
1156
rv.w = ieee754dp_tint(fs);
1157
ieee754_csr.rm = oldrm;
1158
rfmt = w_fmt;
1159
goto copcsr;
1160
}
1161
#endif
1162
1163
#if defined(__mips64)
1164
case fcvtl_op:{
1165
ieee754dp fs;
1166
1167
DPFROMREG(fs, MIPSInst_FS(ir));
1168
rv.l = ieee754dp_tlong(fs);
1169
rfmt = l_fmt;
1170
goto copcsr;
1171
}
1172
1173
case froundl_op:
1174
case ftruncl_op:
1175
case fceill_op:
1176
case ffloorl_op:{
1177
unsigned int oldrm = ieee754_csr.rm;
1178
ieee754dp fs;
1179
1180
DPFROMREG(fs, MIPSInst_FS(ir));
1181
ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))];
1182
rv.l = ieee754dp_tlong(fs);
1183
ieee754_csr.rm = oldrm;
1184
rfmt = l_fmt;
1185
goto copcsr;
1186
}
1187
#endif /* __mips >= 3 */
1188
1189
default:
1190
if (MIPSInst_FUNC(ir) >= fcmp_op) {
1191
unsigned cmpop = MIPSInst_FUNC(ir) - fcmp_op;
1192
ieee754dp fs, ft;
1193
1194
DPFROMREG(fs, MIPSInst_FS(ir));
1195
DPFROMREG(ft, MIPSInst_FT(ir));
1196
rv.w = ieee754dp_cmp(fs, ft,
1197
cmptab[cmpop & 0x7], cmpop & 0x8);
1198
rfmt = -1;
1199
if ((cmpop & 0x8)
1200
&&
1201
ieee754_cxtest
1202
(IEEE754_INVALID_OPERATION))
1203
rcsr = FPU_CSR_INV_X | FPU_CSR_INV_S;
1204
else
1205
goto copcsr;
1206
1207
}
1208
else {
1209
return SIGILL;
1210
}
1211
break;
1212
}
1213
break;
1214
}
1215
1216
case w_fmt:{
1217
ieee754sp fs;
1218
1219
switch (MIPSInst_FUNC(ir)) {
1220
case fcvts_op:
1221
/* convert word to single precision real */
1222
SPFROMREG(fs, MIPSInst_FS(ir));
1223
rv.s = ieee754sp_fint(fs.bits);
1224
rfmt = s_fmt;
1225
goto copcsr;
1226
case fcvtd_op:
1227
/* convert word to double precision real */
1228
SPFROMREG(fs, MIPSInst_FS(ir));
1229
rv.d = ieee754dp_fint(fs.bits);
1230
rfmt = d_fmt;
1231
goto copcsr;
1232
default:
1233
return SIGILL;
1234
}
1235
break;
1236
}
1237
1238
#if defined(__mips64)
1239
case l_fmt:{
1240
switch (MIPSInst_FUNC(ir)) {
1241
case fcvts_op:
1242
/* convert long to single precision real */
1243
rv.s = ieee754sp_flong(ctx->fpr[MIPSInst_FS(ir)]);
1244
rfmt = s_fmt;
1245
goto copcsr;
1246
case fcvtd_op:
1247
/* convert long to double precision real */
1248
rv.d = ieee754dp_flong(ctx->fpr[MIPSInst_FS(ir)]);
1249
rfmt = d_fmt;
1250
goto copcsr;
1251
default:
1252
return SIGILL;
1253
}
1254
break;
1255
}
1256
#endif
1257
1258
default:
1259
return SIGILL;
1260
}
1261
1262
/*
1263
* Update the fpu CSR register for this operation.
1264
* If an exception is required, generate a tidy SIGFPE exception,
1265
* without updating the result register.
1266
* Note: cause exception bits do not accumulate, they are rewritten
1267
* for each op; only the flag/sticky bits accumulate.
1268
*/
1269
ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;
1270
if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {
1271
/*printk ("SIGFPE: fpu csr = %08x\n",ctx->fcr31); */
1272
return SIGFPE;
1273
}
1274
1275
/*
1276
* Now we can safely write the result back to the register file.
1277
*/
1278
switch (rfmt) {
1279
case -1:{
1280
#if __mips >= 4
1281
cond = fpucondbit[MIPSInst_FD(ir) >> 2];
1282
#else
1283
cond = FPU_CSR_COND;
1284
#endif
1285
if (rv.w)
1286
ctx->fcr31 |= cond;
1287
else
1288
ctx->fcr31 &= ~cond;
1289
break;
1290
}
1291
case d_fmt:
1292
DPTOREG(rv.d, MIPSInst_FD(ir));
1293
break;
1294
case s_fmt:
1295
SPTOREG(rv.s, MIPSInst_FD(ir));
1296
break;
1297
case w_fmt:
1298
SITOREG(rv.w, MIPSInst_FD(ir));
1299
break;
1300
#if defined(__mips64)
1301
case l_fmt:
1302
DITOREG(rv.l, MIPSInst_FD(ir));
1303
break;
1304
#endif
1305
default:
1306
return SIGILL;
1307
}
1308
1309
return 0;
1310
}
1311
1312
int fpu_emulator_cop1Handler(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
1313
int has_fpu, void *__user *fault_addr)
1314
{
1315
unsigned long oldepc, prevepc;
1316
mips_instruction insn;
1317
int sig = 0;
1318
1319
oldepc = xcp->cp0_epc;
1320
do {
1321
prevepc = xcp->cp0_epc;
1322
1323
if (!access_ok(VERIFY_READ, xcp->cp0_epc, sizeof(mips_instruction))) {
1324
MIPS_FPU_EMU_INC_STATS(errors);
1325
*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
1326
return SIGBUS;
1327
}
1328
if (__get_user(insn, (mips_instruction __user *) xcp->cp0_epc)) {
1329
MIPS_FPU_EMU_INC_STATS(errors);
1330
*fault_addr = (mips_instruction __user *)xcp->cp0_epc;
1331
return SIGSEGV;
1332
}
1333
if (insn == 0)
1334
xcp->cp0_epc += 4; /* skip nops */
1335
else {
1336
/*
1337
* The 'ieee754_csr' is an alias of
1338
* ctx->fcr31. No need to copy ctx->fcr31 to
1339
* ieee754_csr. But ieee754_csr.rm is ieee
1340
* library modes. (not mips rounding mode)
1341
*/
1342
/* convert to ieee library modes */
1343
ieee754_csr.rm = ieee_rm[ieee754_csr.rm];
1344
sig = cop1Emulate(xcp, ctx, fault_addr);
1345
/* revert to mips rounding mode */
1346
ieee754_csr.rm = mips_rm[ieee754_csr.rm];
1347
}
1348
1349
if (has_fpu)
1350
break;
1351
if (sig)
1352
break;
1353
1354
cond_resched();
1355
} while (xcp->cp0_epc > prevepc);
1356
1357
/* SIGILL indicates a non-fpu instruction */
1358
if (sig == SIGILL && xcp->cp0_epc != oldepc)
1359
/* but if epc has advanced, then ignore it */
1360
sig = 0;
1361
1362
return sig;
1363
}
1364
1365
#ifdef CONFIG_DEBUG_FS
1366
1367
static int fpuemu_stat_get(void *data, u64 *val)
1368
{
1369
int cpu;
1370
unsigned long sum = 0;
1371
for_each_online_cpu(cpu) {
1372
struct mips_fpu_emulator_stats *ps;
1373
local_t *pv;
1374
ps = &per_cpu(fpuemustats, cpu);
1375
pv = (void *)ps + (unsigned long)data;
1376
sum += local_read(pv);
1377
}
1378
*val = sum;
1379
return 0;
1380
}
1381
DEFINE_SIMPLE_ATTRIBUTE(fops_fpuemu_stat, fpuemu_stat_get, NULL, "%llu\n");
1382
1383
extern struct dentry *mips_debugfs_dir;
1384
static int __init debugfs_fpuemu(void)
1385
{
1386
struct dentry *d, *dir;
1387
1388
if (!mips_debugfs_dir)
1389
return -ENODEV;
1390
dir = debugfs_create_dir("fpuemustats", mips_debugfs_dir);
1391
if (!dir)
1392
return -ENOMEM;
1393
1394
#define FPU_STAT_CREATE(M) \
1395
do { \
1396
d = debugfs_create_file(#M , S_IRUGO, dir, \
1397
(void *)offsetof(struct mips_fpu_emulator_stats, M), \
1398
&fops_fpuemu_stat); \
1399
if (!d) \
1400
return -ENOMEM; \
1401
} while (0)
1402
1403
FPU_STAT_CREATE(emulated);
1404
FPU_STAT_CREATE(loads);
1405
FPU_STAT_CREATE(stores);
1406
FPU_STAT_CREATE(cp1ops);
1407
FPU_STAT_CREATE(cp1xops);
1408
FPU_STAT_CREATE(errors);
1409
1410
return 0;
1411
}
1412
__initcall(debugfs_fpuemu);
1413
#endif
1414
1415