PC, KVM, CMA: Fix regression caused by wrong get_order() use
[sfrench/cifs-2.6.git] / arch / powerpc / math-emu / math.c
1 /*
2  * Copyright (C) 1999  Eddie C. Dost  (ecd@atecom.com)
3  */
4
5 #include <linux/types.h>
6 #include <linux/sched.h>
7
8 #include <asm/uaccess.h>
9 #include <asm/reg.h>
10 #include <asm/switch_to.h>
11
12 #include <asm/sfp-machine.h>
13 #include <math-emu/double.h>
14
15 #define FLOATFUNC(x)    extern int x(void *, void *, void *, void *)
16
17 /* The instructions list which may be not implemented by a hardware FPU */
18 FLOATFUNC(fre);
19 FLOATFUNC(frsqrtes);
20 FLOATFUNC(fsqrt);
21 FLOATFUNC(fsqrts);
22 FLOATFUNC(mtfsf);
23 FLOATFUNC(mtfsfi);
24
25 #ifdef CONFIG_MATH_EMULATION_HW_UNIMPLEMENTED
26 #undef FLOATFUNC(x)
27 #define FLOATFUNC(x)    static inline int x(void *op1, void *op2, void *op3, \
28                                                  void *op4) { }
29 #endif
30
31 FLOATFUNC(fadd);
32 FLOATFUNC(fadds);
33 FLOATFUNC(fdiv);
34 FLOATFUNC(fdivs);
35 FLOATFUNC(fmul);
36 FLOATFUNC(fmuls);
37 FLOATFUNC(fsub);
38 FLOATFUNC(fsubs);
39
40 FLOATFUNC(fmadd);
41 FLOATFUNC(fmadds);
42 FLOATFUNC(fmsub);
43 FLOATFUNC(fmsubs);
44 FLOATFUNC(fnmadd);
45 FLOATFUNC(fnmadds);
46 FLOATFUNC(fnmsub);
47 FLOATFUNC(fnmsubs);
48
49 FLOATFUNC(fctiw);
50 FLOATFUNC(fctiwz);
51 FLOATFUNC(frsp);
52
53 FLOATFUNC(fcmpo);
54 FLOATFUNC(fcmpu);
55
56 FLOATFUNC(mcrfs);
57 FLOATFUNC(mffs);
58 FLOATFUNC(mtfsb0);
59 FLOATFUNC(mtfsb1);
60
61 FLOATFUNC(lfd);
62 FLOATFUNC(lfs);
63
64 FLOATFUNC(stfd);
65 FLOATFUNC(stfs);
66 FLOATFUNC(stfiwx);
67
68 FLOATFUNC(fabs);
69 FLOATFUNC(fmr);
70 FLOATFUNC(fnabs);
71 FLOATFUNC(fneg);
72
73 /* Optional */
74 FLOATFUNC(fres);
75 FLOATFUNC(frsqrte);
76 FLOATFUNC(fsel);
77
78
79 #define OP31            0x1f            /*   31 */
80 #define LFS             0x30            /*   48 */
81 #define LFSU            0x31            /*   49 */
82 #define LFD             0x32            /*   50 */
83 #define LFDU            0x33            /*   51 */
84 #define STFS            0x34            /*   52 */
85 #define STFSU           0x35            /*   53 */
86 #define STFD            0x36            /*   54 */
87 #define STFDU           0x37            /*   55 */
88 #define OP59            0x3b            /*   59 */
89 #define OP63            0x3f            /*   63 */
90
91 /* Opcode 31: */
92 /* X-Form: */
93 #define LFSX            0x217           /*  535 */
94 #define LFSUX           0x237           /*  567 */
95 #define LFDX            0x257           /*  599 */
96 #define LFDUX           0x277           /*  631 */
97 #define STFSX           0x297           /*  663 */
98 #define STFSUX          0x2b7           /*  695 */
99 #define STFDX           0x2d7           /*  727 */
100 #define STFDUX          0x2f7           /*  759 */
101 #define STFIWX          0x3d7           /*  983 */
102
103 /* Opcode 59: */
104 /* A-Form: */
105 #define FDIVS           0x012           /*   18 */
106 #define FSUBS           0x014           /*   20 */
107 #define FADDS           0x015           /*   21 */
108 #define FSQRTS          0x016           /*   22 */
109 #define FRES            0x018           /*   24 */
110 #define FMULS           0x019           /*   25 */
111 #define FRSQRTES        0x01a           /*   26 */
112 #define FMSUBS          0x01c           /*   28 */
113 #define FMADDS          0x01d           /*   29 */
114 #define FNMSUBS         0x01e           /*   30 */
115 #define FNMADDS         0x01f           /*   31 */
116
117 /* Opcode 63: */
118 /* A-Form: */
119 #define FDIV            0x012           /*   18 */
120 #define FSUB            0x014           /*   20 */
121 #define FADD            0x015           /*   21 */
122 #define FSQRT           0x016           /*   22 */
123 #define FSEL            0x017           /*   23 */
124 #define FRE             0x018           /*   24 */
125 #define FMUL            0x019           /*   25 */
126 #define FRSQRTE         0x01a           /*   26 */
127 #define FMSUB           0x01c           /*   28 */
128 #define FMADD           0x01d           /*   29 */
129 #define FNMSUB          0x01e           /*   30 */
130 #define FNMADD          0x01f           /*   31 */
131
132 /* X-Form: */
133 #define FCMPU           0x000           /*    0 */
134 #define FRSP            0x00c           /*   12 */
135 #define FCTIW           0x00e           /*   14 */
136 #define FCTIWZ          0x00f           /*   15 */
137 #define FCMPO           0x020           /*   32 */
138 #define MTFSB1          0x026           /*   38 */
139 #define FNEG            0x028           /*   40 */
140 #define MCRFS           0x040           /*   64 */
141 #define MTFSB0          0x046           /*   70 */
142 #define FMR             0x048           /*   72 */
143 #define MTFSFI          0x086           /*  134 */
144 #define FNABS           0x088           /*  136 */
145 #define FABS            0x108           /*  264 */
146 #define MFFS            0x247           /*  583 */
147 #define MTFSF           0x2c7           /*  711 */
148
149
150 #define AB      2
151 #define AC      3
152 #define ABC     4
153 #define D       5
154 #define DU      6
155 #define X       7
156 #define XA      8
157 #define XB      9
158 #define XCR     11
159 #define XCRB    12
160 #define XCRI    13
161 #define XCRL    16
162 #define XE      14
163 #define XEU     15
164 #define XFLB    10
165
166 static int
167 record_exception(struct pt_regs *regs, int eflag)
168 {
169         u32 fpscr;
170
171         fpscr = __FPU_FPSCR;
172
173         if (eflag) {
174                 fpscr |= FPSCR_FX;
175                 if (eflag & EFLAG_OVERFLOW)
176                         fpscr |= FPSCR_OX;
177                 if (eflag & EFLAG_UNDERFLOW)
178                         fpscr |= FPSCR_UX;
179                 if (eflag & EFLAG_DIVZERO)
180                         fpscr |= FPSCR_ZX;
181                 if (eflag & EFLAG_INEXACT)
182                         fpscr |= FPSCR_XX;
183                 if (eflag & EFLAG_INVALID)
184                         fpscr |= FPSCR_VX;
185                 if (eflag & EFLAG_VXSNAN)
186                         fpscr |= FPSCR_VXSNAN;
187                 if (eflag & EFLAG_VXISI)
188                         fpscr |= FPSCR_VXISI;
189                 if (eflag & EFLAG_VXIDI)
190                         fpscr |= FPSCR_VXIDI;
191                 if (eflag & EFLAG_VXZDZ)
192                         fpscr |= FPSCR_VXZDZ;
193                 if (eflag & EFLAG_VXIMZ)
194                         fpscr |= FPSCR_VXIMZ;
195                 if (eflag & EFLAG_VXVC)
196                         fpscr |= FPSCR_VXVC;
197                 if (eflag & EFLAG_VXSOFT)
198                         fpscr |= FPSCR_VXSOFT;
199                 if (eflag & EFLAG_VXSQRT)
200                         fpscr |= FPSCR_VXSQRT;
201                 if (eflag & EFLAG_VXCVI)
202                         fpscr |= FPSCR_VXCVI;
203         }
204
205 //      fpscr &= ~(FPSCR_VX);
206         if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
207                      FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
208                      FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI))
209                 fpscr |= FPSCR_VX;
210
211         fpscr &= ~(FPSCR_FEX);
212         if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) ||
213             ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) ||
214             ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) ||
215             ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) ||
216             ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE)))
217                 fpscr |= FPSCR_FEX;
218
219         __FPU_FPSCR = fpscr;
220
221         return (fpscr & FPSCR_FEX) ? 1 : 0;
222 }
223
224 int
225 do_mathemu(struct pt_regs *regs)
226 {
227         void *op0 = 0, *op1 = 0, *op2 = 0, *op3 = 0;
228         unsigned long pc = regs->nip;
229         signed short sdisp;
230         u32 insn = 0;
231         int idx = 0;
232         int (*func)(void *, void *, void *, void *);
233         int type = 0;
234         int eflag, trap;
235
236         if (get_user(insn, (u32 *)pc))
237                 return -EFAULT;
238
239         switch (insn >> 26) {
240         case LFS:       func = lfs;     type = D;       break;
241         case LFSU:      func = lfs;     type = DU;      break;
242         case LFD:       func = lfd;     type = D;       break;
243         case LFDU:      func = lfd;     type = DU;      break;
244         case STFS:      func = stfs;    type = D;       break;
245         case STFSU:     func = stfs;    type = DU;      break;
246         case STFD:      func = stfd;    type = D;       break;
247         case STFDU:     func = stfd;    type = DU;      break;
248
249         case OP31:
250                 switch ((insn >> 1) & 0x3ff) {
251                 case LFSX:      func = lfs;     type = XE;      break;
252                 case LFSUX:     func = lfs;     type = XEU;     break;
253                 case LFDX:      func = lfd;     type = XE;      break;
254                 case LFDUX:     func = lfd;     type = XEU;     break;
255                 case STFSX:     func = stfs;    type = XE;      break;
256                 case STFSUX:    func = stfs;    type = XEU;     break;
257                 case STFDX:     func = stfd;    type = XE;      break;
258                 case STFDUX:    func = stfd;    type = XEU;     break;
259                 case STFIWX:    func = stfiwx;  type = XE;      break;
260                 default:
261                         goto illegal;
262                 }
263                 break;
264
265         case OP59:
266                 switch ((insn >> 1) & 0x1f) {
267                 case FDIVS:     func = fdivs;   type = AB;      break;
268                 case FSUBS:     func = fsubs;   type = AB;      break;
269                 case FADDS:     func = fadds;   type = AB;      break;
270                 case FSQRTS:    func = fsqrts;  type = XB;      break;
271                 case FRES:      func = fres;    type = XB;      break;
272                 case FMULS:     func = fmuls;   type = AC;      break;
273                 case FRSQRTES:  func = frsqrtes;type = XB;      break;
274                 case FMSUBS:    func = fmsubs;  type = ABC;     break;
275                 case FMADDS:    func = fmadds;  type = ABC;     break;
276                 case FNMSUBS:   func = fnmsubs; type = ABC;     break;
277                 case FNMADDS:   func = fnmadds; type = ABC;     break;
278                 default:
279                         goto illegal;
280                 }
281                 break;
282
283         case OP63:
284                 if (insn & 0x20) {
285                         switch ((insn >> 1) & 0x1f) {
286                         case FDIV:      func = fdiv;    type = AB;      break;
287                         case FSUB:      func = fsub;    type = AB;      break;
288                         case FADD:      func = fadd;    type = AB;      break;
289                         case FSQRT:     func = fsqrt;   type = XB;      break;
290                         case FRE:       func = fre;     type = XB;      break;
291                         case FSEL:      func = fsel;    type = ABC;     break;
292                         case FMUL:      func = fmul;    type = AC;      break;
293                         case FRSQRTE:   func = frsqrte; type = XB;      break;
294                         case FMSUB:     func = fmsub;   type = ABC;     break;
295                         case FMADD:     func = fmadd;   type = ABC;     break;
296                         case FNMSUB:    func = fnmsub;  type = ABC;     break;
297                         case FNMADD:    func = fnmadd;  type = ABC;     break;
298                         default:
299                                 goto illegal;
300                         }
301                         break;
302                 }
303
304                 switch ((insn >> 1) & 0x3ff) {
305                 case FCMPU:     func = fcmpu;   type = XCR;     break;
306                 case FRSP:      func = frsp;    type = XB;      break;
307                 case FCTIW:     func = fctiw;   type = XB;      break;
308                 case FCTIWZ:    func = fctiwz;  type = XB;      break;
309                 case FCMPO:     func = fcmpo;   type = XCR;     break;
310                 case MTFSB1:    func = mtfsb1;  type = XCRB;    break;
311                 case FNEG:      func = fneg;    type = XB;      break;
312                 case MCRFS:     func = mcrfs;   type = XCRL;    break;
313                 case MTFSB0:    func = mtfsb0;  type = XCRB;    break;
314                 case FMR:       func = fmr;     type = XB;      break;
315                 case MTFSFI:    func = mtfsfi;  type = XCRI;    break;
316                 case FNABS:     func = fnabs;   type = XB;      break;
317                 case FABS:      func = fabs;    type = XB;      break;
318                 case MFFS:      func = mffs;    type = X;       break;
319                 case MTFSF:     func = mtfsf;   type = XFLB;    break;
320                 default:
321                         goto illegal;
322                 }
323                 break;
324
325         default:
326                 goto illegal;
327         }
328
329         switch (type) {
330         case AB:
331                 op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
332                 op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
333                 op2 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
334                 break;
335
336         case AC:
337                 op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
338                 op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
339                 op2 = (void *)&current->thread.TS_FPR((insn >>  6) & 0x1f);
340                 break;
341
342         case ABC:
343                 op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
344                 op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
345                 op2 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
346                 op3 = (void *)&current->thread.TS_FPR((insn >>  6) & 0x1f);
347                 break;
348
349         case D:
350                 idx = (insn >> 16) & 0x1f;
351                 sdisp = (insn & 0xffff);
352                 op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
353                 op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
354                 break;
355
356         case DU:
357                 idx = (insn >> 16) & 0x1f;
358                 if (!idx)
359                         goto illegal;
360
361                 sdisp = (insn & 0xffff);
362                 op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
363                 op1 = (void *)(regs->gpr[idx] + sdisp);
364                 break;
365
366         case X:
367                 op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
368                 break;
369
370         case XA:
371                 op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
372                 op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
373                 break;
374
375         case XB:
376                 op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
377                 op1 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
378                 break;
379
380         case XE:
381                 idx = (insn >> 16) & 0x1f;
382                 op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
383                 op1 = (void *)((idx ? regs->gpr[idx] : 0)
384                                 + regs->gpr[(insn >> 11) & 0x1f]);
385                 break;
386
387         case XEU:
388                 idx = (insn >> 16) & 0x1f;
389                 if (!idx)
390                         goto illegal;
391                 op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
392                 op1 = (void *)(regs->gpr[idx]
393                                 + regs->gpr[(insn >> 11) & 0x1f]);
394                 break;
395
396         case XCR:
397                 op0 = (void *)&regs->ccr;
398                 op1 = (void *)((insn >> 23) & 0x7);
399                 op2 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
400                 op3 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
401                 break;
402
403         case XCRL:
404                 op0 = (void *)&regs->ccr;
405                 op1 = (void *)((insn >> 23) & 0x7);
406                 op2 = (void *)((insn >> 18) & 0x7);
407                 break;
408
409         case XCRB:
410                 op0 = (void *)((insn >> 21) & 0x1f);
411                 break;
412
413         case XCRI:
414                 op0 = (void *)((insn >> 23) & 0x7);
415                 op1 = (void *)((insn >> 12) & 0xf);
416                 break;
417
418         case XFLB:
419                 op0 = (void *)((insn >> 17) & 0xff);
420                 op1 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
421                 break;
422
423         default:
424                 goto illegal;
425         }
426
427         /*
428          * If we support a HW FPU, we need to ensure the FP state
429          * is flushed into the thread_struct before attempting
430          * emulation
431          */
432         flush_fp_to_thread(current);
433
434         eflag = func(op0, op1, op2, op3);
435
436         if (insn & 1) {
437                 regs->ccr &= ~(0x0f000000);
438                 regs->ccr |= (__FPU_FPSCR >> 4) & 0x0f000000;
439         }
440
441         trap = record_exception(regs, eflag);
442         if (trap)
443                 return 1;
444
445         switch (type) {
446         case DU:
447         case XEU:
448                 regs->gpr[idx] = (unsigned long)op1;
449                 break;
450
451         default:
452                 break;
453         }
454
455         regs->nip += 4;
456         return 0;
457
458 illegal:
459         return -ENOSYS;
460 }