~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/sh/math-emu/math.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * arch/sh/math-emu/math.c
  3  *
  4  * Copyright (C) 2006 Takashi YOSHII <takasi-y@ops.dti.ne.jp>
  5  *
  6  * This file is subject to the terms and conditions of the GNU General Public
  7  * License.  See the file "COPYING" in the main directory of this archive
  8  * for more details.
  9  */
 10 #include <linux/kernel.h>
 11 #include <linux/errno.h>
 12 #include <linux/types.h>
 13 #include <linux/sched/signal.h>
 14 #include <linux/signal.h>
 15 #include <linux/perf_event.h>
 16 
 17 #include <linux/uaccess.h>
 18 
 19 #include <asm/fpu.h>
 20 #include <asm/processor.h>
 21 #include <asm/io.h>
 22 
 23 #include "sfp-util.h"
 24 #include <math-emu/soft-fp.h>
 25 #include <math-emu/single.h>
 26 #include <math-emu/double.h>
 27 
 28 #define FPUL            (fregs->fpul)
 29 #define FPSCR           (fregs->fpscr)
 30 #define FPSCR_RM        (FPSCR&3)
 31 #define FPSCR_DN        ((FPSCR>>18)&1)
 32 #define FPSCR_PR        ((FPSCR>>19)&1)
 33 #define FPSCR_SZ        ((FPSCR>>20)&1)
 34 #define FPSCR_FR        ((FPSCR>>21)&1)
 35 #define FPSCR_MASK      0x003fffffUL
 36 
 37 #define BANK(n) (n^(FPSCR_FR?16:0))
 38 #define FR      ((unsigned long*)(fregs->fp_regs))
 39 #define FR0     (FR[BANK(0)])
 40 #define FRn     (FR[BANK(n)])
 41 #define FRm     (FR[BANK(m)])
 42 #define DR      ((unsigned long long*)(fregs->fp_regs))
 43 #define DRn     (DR[BANK(n)/2])
 44 #define DRm     (DR[BANK(m)/2])
 45 
 46 #define XREG(n) (n^16)
 47 #define XFn     (FR[BANK(XREG(n))])
 48 #define XFm     (FR[BANK(XREG(m))])
 49 #define XDn     (DR[BANK(XREG(n))/2])
 50 #define XDm     (DR[BANK(XREG(m))/2])
 51 
 52 #define R0      (regs->regs[0])
 53 #define Rn      (regs->regs[n])
 54 #define Rm      (regs->regs[m])
 55 
 56 #define MWRITE(d,a)     ({if(put_user(d, (typeof (d) __user *)a)) return -EFAULT;})
 57 #define MREAD(d,a)      ({if(get_user(d, (typeof (d) __user *)a)) return -EFAULT;})
 58 
 59 #define PACK_S(r,f)     FP_PACK_SP(&r,f)
 60 #define UNPACK_S(f,r)   FP_UNPACK_SP(f,&r)
 61 #define PACK_D(r,f) \
 62         {u32 t[2]; FP_PACK_DP(t,f); ((u32*)&r)[0]=t[1]; ((u32*)&r)[1]=t[0];}
 63 #define UNPACK_D(f,r) \
 64         {u32 t[2]; t[0]=((u32*)&r)[1]; t[1]=((u32*)&r)[0]; FP_UNPACK_DP(f,t);}
 65 
 66 // 2 args instructions.
 67 #define BOTH_PRmn(op,x) \
 68         FP_DECL_EX; if(FPSCR_PR) op(D,x,DRm,DRn); else op(S,x,FRm,FRn);
 69 
 70 #define CMP_X(SZ,R,M,N) do{ \
 71         FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); \
 72         UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \
 73         FP_CMP_##SZ(R, Fn, Fm, 2); }while(0)
 74 #define EQ_X(SZ,R,M,N) do{ \
 75         FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); \
 76         UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \
 77         FP_CMP_EQ_##SZ(R, Fn, Fm); }while(0)
 78 #define CMP(OP) ({ int r; BOTH_PRmn(OP##_X,r); r; })
 79 
 80 static int
 81 fcmp_gt(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
 82 {
 83         if (CMP(CMP) > 0)
 84                 regs->sr |= 1;
 85         else
 86                 regs->sr &= ~1;
 87 
 88         return 0;
 89 }
 90 
 91 static int
 92 fcmp_eq(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
 93 {
 94         if (CMP(CMP /*EQ*/) == 0)
 95                 regs->sr |= 1;
 96         else
 97                 regs->sr &= ~1;
 98         return 0;
 99 }
100 
101 #define ARITH_X(SZ,OP,M,N) do{ \
102         FP_DECL_##SZ(Fm); FP_DECL_##SZ(Fn); FP_DECL_##SZ(Fr); \
103         UNPACK_##SZ(Fm, M); UNPACK_##SZ(Fn, N); \
104         FP_##OP##_##SZ(Fr, Fn, Fm); \
105         PACK_##SZ(N, Fr); }while(0)
106 
107 static int
108 fadd(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
109 {
110         BOTH_PRmn(ARITH_X, ADD);
111         return 0;
112 }
113 
114 static int
115 fsub(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
116 {
117         BOTH_PRmn(ARITH_X, SUB);
118         return 0;
119 }
120 
121 static int
122 fmul(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
123 {
124         BOTH_PRmn(ARITH_X, MUL);
125         return 0;
126 }
127 
128 static int
129 fdiv(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
130 {
131         BOTH_PRmn(ARITH_X, DIV);
132         return 0;
133 }
134 
135 static int
136 fmac(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
137 {
138         FP_DECL_EX;
139         FP_DECL_S(Fr);
140         FP_DECL_S(Ft);
141         FP_DECL_S(F0);
142         FP_DECL_S(Fm);
143         FP_DECL_S(Fn);
144         UNPACK_S(F0, FR0);
145         UNPACK_S(Fm, FRm);
146         UNPACK_S(Fn, FRn);
147         FP_MUL_S(Ft, Fm, F0);
148         FP_ADD_S(Fr, Fn, Ft);
149         PACK_S(FRn, Fr);
150         return 0;
151 }
152 
153 // to process fmov's extension (odd n for DR access XD).
154 #define FMOV_EXT(x) if(x&1) x+=16-1
155 
156 static int
157 fmov_idx_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
158              int n)
159 {
160         if (FPSCR_SZ) {
161                 FMOV_EXT(n);
162                 MREAD(FRn, Rm + R0 + 4);
163                 n++;
164                 MREAD(FRn, Rm + R0);
165         } else {
166                 MREAD(FRn, Rm + R0);
167         }
168 
169         return 0;
170 }
171 
172 static int
173 fmov_mem_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
174              int n)
175 {
176         if (FPSCR_SZ) {
177                 FMOV_EXT(n);
178                 MREAD(FRn, Rm + 4);
179                 n++;
180                 MREAD(FRn, Rm);
181         } else {
182                 MREAD(FRn, Rm);
183         }
184 
185         return 0;
186 }
187 
188 static int
189 fmov_inc_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
190              int n)
191 {
192         if (FPSCR_SZ) {
193                 FMOV_EXT(n);
194                 MREAD(FRn, Rm + 4);
195                 n++;
196                 MREAD(FRn, Rm);
197                 Rm += 8;
198         } else {
199                 MREAD(FRn, Rm);
200                 Rm += 4;
201         }
202 
203         return 0;
204 }
205 
206 static int
207 fmov_reg_idx(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
208              int n)
209 {
210         if (FPSCR_SZ) {
211                 FMOV_EXT(m);
212                 MWRITE(FRm, Rn + R0 + 4);
213                 m++;
214                 MWRITE(FRm, Rn + R0);
215         } else {
216                 MWRITE(FRm, Rn + R0);
217         }
218 
219         return 0;
220 }
221 
222 static int
223 fmov_reg_mem(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
224              int n)
225 {
226         if (FPSCR_SZ) {
227                 FMOV_EXT(m);
228                 MWRITE(FRm, Rn + 4);
229                 m++;
230                 MWRITE(FRm, Rn);
231         } else {
232                 MWRITE(FRm, Rn);
233         }
234 
235         return 0;
236 }
237 
238 static int
239 fmov_reg_dec(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
240              int n)
241 {
242         if (FPSCR_SZ) {
243                 FMOV_EXT(m);
244                 Rn -= 8;
245                 MWRITE(FRm, Rn + 4);
246                 m++;
247                 MWRITE(FRm, Rn);
248         } else {
249                 Rn -= 4;
250                 MWRITE(FRm, Rn);
251         }
252 
253         return 0;
254 }
255 
256 static int
257 fmov_reg_reg(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m,
258              int n)
259 {
260         if (FPSCR_SZ) {
261                 FMOV_EXT(m);
262                 FMOV_EXT(n);
263                 DRn = DRm;
264         } else {
265                 FRn = FRm;
266         }
267 
268         return 0;
269 }
270 
271 static int
272 fnop_mn(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int m, int n)
273 {
274         return -EINVAL;
275 }
276 
277 // 1 arg instructions.
278 #define NOTYETn(i) static int i(struct sh_fpu_soft_struct *fregs, int n) \
279         { printk( #i " not yet done.\n"); return 0; }
280 
281 NOTYETn(ftrv)
282 NOTYETn(fsqrt)
283 NOTYETn(fipr)
284 NOTYETn(fsca)
285 NOTYETn(fsrra)
286 
287 #define EMU_FLOAT_X(SZ,N) do { \
288         FP_DECL_##SZ(Fn); \
289         FP_FROM_INT_##SZ(Fn, FPUL, 32, int); \
290         PACK_##SZ(N, Fn); }while(0)
291 static int ffloat(struct sh_fpu_soft_struct *fregs, int n)
292 {
293         FP_DECL_EX;
294 
295         if (FPSCR_PR)
296                 EMU_FLOAT_X(D, DRn);
297         else
298                 EMU_FLOAT_X(S, FRn);
299 
300         return 0;
301 }
302 
303 #define EMU_FTRC_X(SZ,N) do { \
304         FP_DECL_##SZ(Fn); \
305         UNPACK_##SZ(Fn, N); \
306         FP_TO_INT_##SZ(FPUL, Fn, 32, 1); }while(0)
307 static int ftrc(struct sh_fpu_soft_struct *fregs, int n)
308 {
309         FP_DECL_EX;
310 
311         if (FPSCR_PR)
312                 EMU_FTRC_X(D, DRn);
313         else
314                 EMU_FTRC_X(S, FRn);
315 
316         return 0;
317 }
318 
319 static int fcnvsd(struct sh_fpu_soft_struct *fregs, int n)
320 {
321         FP_DECL_EX;
322         FP_DECL_S(Fn);
323         FP_DECL_D(Fr);
324         UNPACK_S(Fn, FPUL);
325         FP_CONV(D, S, 2, 1, Fr, Fn);
326         PACK_D(DRn, Fr);
327         return 0;
328 }
329 
330 static int fcnvds(struct sh_fpu_soft_struct *fregs, int n)
331 {
332         FP_DECL_EX;
333         FP_DECL_D(Fn);
334         FP_DECL_S(Fr);
335         UNPACK_D(Fn, DRn);
336         FP_CONV(S, D, 1, 2, Fr, Fn);
337         PACK_S(FPUL, Fr);
338         return 0;
339 }
340 
341 static int fxchg(struct sh_fpu_soft_struct *fregs, int flag)
342 {
343         FPSCR ^= flag;
344         return 0;
345 }
346 
347 static int fsts(struct sh_fpu_soft_struct *fregs, int n)
348 {
349         FRn = FPUL;
350         return 0;
351 }
352 
353 static int flds(struct sh_fpu_soft_struct *fregs, int n)
354 {
355         FPUL = FRn;
356         return 0;
357 }
358 
359 static int fneg(struct sh_fpu_soft_struct *fregs, int n)
360 {
361         FRn ^= (1 << (_FP_W_TYPE_SIZE - 1));
362         return 0;
363 }
364 
365 static int fabs(struct sh_fpu_soft_struct *fregs, int n)
366 {
367         FRn &= ~(1 << (_FP_W_TYPE_SIZE - 1));
368         return 0;
369 }
370 
371 static int fld0(struct sh_fpu_soft_struct *fregs, int n)
372 {
373         FRn = 0;
374         return 0;
375 }
376 
377 static int fld1(struct sh_fpu_soft_struct *fregs, int n)
378 {
379         FRn = (_FP_EXPBIAS_S << (_FP_FRACBITS_S - 1));
380         return 0;
381 }
382 
383 static int fnop_n(struct sh_fpu_soft_struct *fregs, int n)
384 {
385         return -EINVAL;
386 }
387 
388 /// Instruction decoders.
389 
390 static int id_fxfd(struct sh_fpu_soft_struct *, int);
391 static int id_fnxd(struct sh_fpu_soft_struct *, struct pt_regs *, int, int);
392 
393 static int (*fnxd[])(struct sh_fpu_soft_struct *, int) = {
394         fsts, flds, ffloat, ftrc, fneg, fabs, fsqrt, fsrra,
395         fld0, fld1, fcnvsd, fcnvds, fnop_n, fnop_n, fipr, id_fxfd
396 };
397 
398 static int (*fnmx[])(struct sh_fpu_soft_struct *, struct pt_regs *, int, int) = {
399         fadd, fsub, fmul, fdiv, fcmp_eq, fcmp_gt, fmov_idx_reg, fmov_reg_idx,
400         fmov_mem_reg, fmov_inc_reg, fmov_reg_mem, fmov_reg_dec,
401         fmov_reg_reg, id_fnxd, fmac, fnop_mn};
402 
403 static int id_fxfd(struct sh_fpu_soft_struct *fregs, int x)
404 {
405         const int flag[] = { FPSCR_SZ, FPSCR_PR, FPSCR_FR, 0 };
406         switch (x & 3) {
407         case 3:
408                 fxchg(fregs, flag[x >> 2]);
409                 break;
410         case 1:
411                 ftrv(fregs, x - 1);
412                 break;
413         default:
414                 fsca(fregs, x);
415         }
416         return 0;
417 }
418 
419 static int
420 id_fnxd(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, int x, int n)
421 {
422         return (fnxd[x])(fregs, n);
423 }
424 
425 static int
426 id_fnmx(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, u16 code)
427 {
428         int n = (code >> 8) & 0xf, m = (code >> 4) & 0xf, x = code & 0xf;
429         return (fnmx[x])(fregs, regs, m, n);
430 }
431 
432 static int
433 id_sys(struct sh_fpu_soft_struct *fregs, struct pt_regs *regs, u16 code)
434 {
435         int n = ((code >> 8) & 0xf);
436         unsigned long *reg = (code & 0x0010) ? &FPUL : &FPSCR;
437 
438         switch (code & 0xf0ff) {
439         case 0x005a:
440         case 0x006a:
441                 Rn = *reg;
442                 break;
443         case 0x405a:
444         case 0x406a:
445                 *reg = Rn;
446                 break;
447         case 0x4052:
448         case 0x4062:
449                 Rn -= 4;
450                 MWRITE(*reg, Rn);
451                 break;
452         case 0x4056:
453         case 0x4066:
454                 MREAD(*reg, Rn);
455                 Rn += 4;
456                 break;
457         default:
458                 return -EINVAL;
459         }
460 
461         return 0;
462 }
463 
464 static int fpu_emulate(u16 code, struct sh_fpu_soft_struct *fregs, struct pt_regs *regs)
465 {
466         if ((code & 0xf000) == 0xf000)
467                 return id_fnmx(fregs, regs, code);
468         else
469                 return id_sys(fregs, regs, code);
470 }
471 
472 /**
473  * fpu_init - Initialize FPU registers
474  * @fpu: Pointer to software emulated FPU registers.
475  */
476 static void fpu_init(struct sh_fpu_soft_struct *fpu)
477 {
478         int i;
479 
480         fpu->fpscr = FPSCR_INIT;
481         fpu->fpul = 0;
482 
483         for (i = 0; i < 16; i++) {
484                 fpu->fp_regs[i] = 0;
485                 fpu->xfp_regs[i]= 0;
486         }
487 }
488 
489 /**
490  * do_fpu_inst - Handle reserved instructions for FPU emulation
491  * @inst: instruction code.
492  * @regs: registers on stack.
493  */
494 int do_fpu_inst(unsigned short inst, struct pt_regs *regs)
495 {
496         struct task_struct *tsk = current;
497         struct sh_fpu_soft_struct *fpu = &(tsk->thread.xstate->softfpu);
498 
499         perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
500 
501         if (!(task_thread_info(tsk)->status & TS_USEDFPU)) {
502                 /* initialize once. */
503                 fpu_init(fpu);
504                 task_thread_info(tsk)->status |= TS_USEDFPU;
505         }
506 
507         return fpu_emulate(inst, fpu, regs);
508 }
509 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php