File: /usr/src/linux/arch/s390x/kernel/mathemu.c

1     /*
2      *  arch/s390/kernel/mathemu.c
3      *
4      *  S390 version
5      *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
6      *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
7      *
8      * 'mathemu.c' handles IEEE instructions on a S390 processor
9      * that does not have the IEEE fpu
10      */
11     
12     #include <linux/config.h>
13     #include <linux/kernel.h>
14     #include <linux/errno.h>
15     #include <linux/ptrace.h>
16     
17     #include <asm/uaccess.h>
18     #include <asm/mathemu.h>
19     
20     #ifdef CONFIG_SYSCTL
21     int sysctl_ieee_emulation_warnings=1;
22     #endif
23     
24     static void display_emulation_not_implemented(char *instr)
25     {
26     	struct pt_regs *regs;
27     	__u16 *location;
28     	
29     #if CONFIG_SYSCTL
30     	if(sysctl_ieee_emulation_warnings)
31     #endif
32     	{
33     		regs=current->thread.regs;
34     		location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
35     		printk("%s ieee fpu instruction not emulated process name: %s pid: %d \n",
36     		       instr,
37     		       current->comm, current->pid);
38     		printk("%s's PSW:    %08lx %08lx\n",instr,
39     		       (unsigned long) regs->psw.mask,
40     		       (unsigned long) location);
41     	}
42     }
43     
44     
45     static void set_CC_df(__u64 val1,__u64 val2) {
46             int rc;
47             rc = __cmpdf2(val1,val2);
48             current->thread.regs->psw.mask &= 0xFFFFCFFFFFFFFFFFL;
49             switch (rc) {
50                     case -1:
51                             current->thread.regs->psw.mask |= 0x0000100000000000L;
52                             break;
53                     case 1:
54                             current->thread.regs->psw.mask |= 0x0000200000000000L;
55                             break;
56             }
57     }
58     
59     static void set_CC_sf(__u32 val1,__u32 val2) {
60             int rc;
61             rc = __cmpsf2(val1,val2);
62             current->thread.regs->psw.mask &= 0xFFFFCFFFFFFFFFFF;
63             switch (rc) {
64                     case -1:
65                             current->thread.regs->psw.mask |= 0x0000100000000000L;
66                             break;
67                     case 1:
68                             current->thread.regs->psw.mask |= 0x0000200000000000L;
69                             break;
70             }
71     }
72     
73     
74     static void emu_adb (int rx, __u64 val) {
75             current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,val);
76             set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
77     }
78     
79     static void emu_adbr (int rx, int ry) {
80             current->thread.fp_regs.fprs[rx].d = __adddf3(current->thread.fp_regs.fprs[rx].d,
81                                              current->thread.fp_regs.fprs[ry].d);
82             set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
83     }
84     
85     static void emu_aeb (int rx, __u32 val) {
86             current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,val);
87             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
88     }
89     
90     static void emu_aebr (int rx, int ry) {
91             current->thread.fp_regs.fprs[rx].f = __addsf3(current->thread.fp_regs.fprs[rx].f,
92                                             current->thread.fp_regs.fprs[ry].f);
93             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
94     }
95     
96     static void emu_axbr (int rx, int ry) {
97             display_emulation_not_implemented("axbr");
98     }
99     
100     static void emu_cdb (int rx, __u64 val) {
101             set_CC_df(current->thread.fp_regs.fprs[rx].d,val);
102     }
103     
104     static void emu_cdbr (int rx, int ry) {
105             set_CC_df(current->thread.fp_regs.fprs[rx].d,current->thread.fp_regs.fprs[ry].d);
106     }
107     
108     static void emu_cdfbr (int rx, int ry) {
109             current->thread.fp_regs.fprs[rx].d =
110                          __floatsidf(current->thread.regs->gprs[ry]);
111     }
112     
113     static void emu_ceb (int rx, __u32 val) {
114             set_CC_sf(current->thread.fp_regs.fprs[rx].f,val);
115     }
116     
117     static void emu_cebr (int rx, int ry) {
118             set_CC_sf(current->thread.fp_regs.fprs[rx].f,current->thread.fp_regs.fprs[ry].f);
119     }
120     
121     static void emu_cefbr (int rx, int ry) {
122             current->thread.fp_regs.fprs[rx].f =
123                          __floatsisf(current->thread.regs->gprs[ry]);
124     }
125     
126     static void emu_cfdbr (int rx, int ry, int mask) {
127             current->thread.regs->gprs[rx] =
128                          __fixdfsi(current->thread.fp_regs.fprs[ry].d);
129     }
130     
131     static void emu_cfebr (int rx, int ry, int mask) {
132             current->thread.regs->gprs[rx] =
133                          __fixsfsi(current->thread.fp_regs.fprs[ry].f);
134     }
135     
136     static void emu_cfxbr (int rx, int ry, int mask) {
137             display_emulation_not_implemented("cfxbr");
138     }
139     
140     static void emu_cxbr (int rx, int ry) {
141             display_emulation_not_implemented("cxbr");
142     }
143     
144     static void emu_cxfbr (int rx, int ry) {
145             display_emulation_not_implemented("cxfbr");
146     }
147     
148     static void emu_ddb (int rx, __u64 val) {
149             current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,val);
150             set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
151     }
152     
153     static void emu_ddbr (int rx, int ry) {
154             current->thread.fp_regs.fprs[rx].d = __divdf3(current->thread.fp_regs.fprs[rx].d,
155                                              current->thread.fp_regs.fprs[ry].d);
156             set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
157     }
158     
159     static void emu_deb (int rx, __u32 val) {
160             current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,val);
161             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
162     }
163     
164     static void emu_debr (int rx, int ry) {
165             current->thread.fp_regs.fprs[rx].f = __divsf3(current->thread.fp_regs.fprs[rx].f,
166                                              current->thread.fp_regs.fprs[ry].f);
167             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
168     }
169     
170     static void emu_didbr (int rx, int ry, int mask) {
171             display_emulation_not_implemented("didbr");
172     }
173     
174     static void emu_diebr (int rx, int ry, int mask) {
175             display_emulation_not_implemented("diebr");
176     }
177     
178     static void emu_dxbr (int rx, int ry) {
179             display_emulation_not_implemented("dxbr");
180     }
181     
182     static void emu_efpc (int rx, int ry) {
183             display_emulation_not_implemented("efpc");
184     }
185     
186     static void emu_fidbr (int rx, int ry, int mask) {
187             display_emulation_not_implemented("fidbr");
188     }
189     
190     static void emu_fiebr (int rx, int ry, int mask) {
191             display_emulation_not_implemented("fiebr");
192     }
193     
194     static void emu_fixbr (int rx, int ry, int mask) {
195             display_emulation_not_implemented("fixbr");
196     }
197     
198     static void emu_kdb (int rx, __u64 val) {
199             display_emulation_not_implemented("kdb");
200     }
201     
202     static void emu_kdbr (int rx, int ry) {
203             display_emulation_not_implemented("kdbr");
204     }
205     
206     static void emu_keb (int rx, __u32 val) {
207             display_emulation_not_implemented("keb");
208     }
209     
210     static void emu_kebr (int rx, int ry) {
211             display_emulation_not_implemented("kebr");
212     }
213     
214     static void emu_kxbr (int rx, int ry) {
215             display_emulation_not_implemented("kxbr");
216     }
217     
218     static void emu_lcdbr (int rx, int ry) {
219             current->thread.fp_regs.fprs[rx].d =
220             __negdf2(current->thread.fp_regs.fprs[ry].d);
221             set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
222     }
223     
224     static void emu_lcebr (int rx, int ry) {
225             current->thread.fp_regs.fprs[rx].f =
226             __negsf2(current->thread.fp_regs.fprs[ry].f);
227             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
228     }
229     
230     static void emu_lcxbr (int rx, int ry) {
231             display_emulation_not_implemented("lcxbr");
232     }
233     
234     static void emu_ldeb (int rx, __u32 val) {
235             current->thread.fp_regs.fprs[rx].d = __extendsfdf2(val);
236     }
237     
238     static void emu_ldebr (int rx, int ry) {
239             current->thread.fp_regs.fprs[rx].d =
240             __extendsfdf2(current->thread.fp_regs.fprs[ry].f);
241     }
242     
243     static void emu_ldxbr (int rx, int ry) {
244             display_emulation_not_implemented("ldxbr");
245     }
246     
247     static void emu_ledbr (int rx, int ry) {
248             current->thread.fp_regs.fprs[rx].f = __truncdfsf2(current->thread.fp_regs.fprs[ry].d);
249             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
250     }
251     
252     static void emu_lexbr (int rx, int ry) {
253             display_emulation_not_implemented("lexbr");
254     }
255     
256     static void emu_lndbr (int rx, int ry) {
257             display_emulation_not_implemented("lndbr");
258     }
259     
260     static void emu_lnebr (int rx, int ry) {
261             display_emulation_not_implemented("lnebr");
262     }
263     
264     static void emu_lnxbr (int rx, int ry) {
265             display_emulation_not_implemented("lnxbr");
266     }
267     
268     static void emu_lpdbr (int rx, int ry) {
269             current->thread.fp_regs.fprs[rx].d = __absdf2(current->thread.fp_regs.fprs[ry].d);
270             set_CC_df(current->thread.fp_regs.fprs[rx].d,0);
271     }
272     
273     static void emu_lpebr (int rx, int ry) {
274             current->thread.fp_regs.fprs[rx].f = __abssf2(current->thread.fp_regs.fprs[ry].f);
275             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
276     }
277     
278     static void emu_lpxbr (int rx, int ry) {
279             display_emulation_not_implemented("lpxbr");
280     }
281     
282     static void emu_ltdbr (int rx, int ry) {
283             current->thread.fp_regs.fprs[rx].d = current->thread.fp_regs.fprs[ry].d;
284             set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
285     }
286     
287     static void emu_ltebr (int rx, int ry) {
288             current->thread.fp_regs.fprs[rx].f = current->thread.fp_regs.fprs[ry].f;
289             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
290     }
291     
292     static void emu_ltxbr (int rx, int ry) {
293             display_emulation_not_implemented("ltxbr");
294     }
295     
296     static void emu_lxdb (int rx, __u64 val) {
297             display_emulation_not_implemented("lxdb");
298     }
299     
300     static void emu_lxdbr (int rx, int ry) {
301             display_emulation_not_implemented("lxdbr");
302     }
303     
304     static void emu_lxeb (int rx, __u32 val) {
305             display_emulation_not_implemented("lxeb");
306     }
307     
308     static void emu_lxebr (int rx, int ry) {
309             display_emulation_not_implemented("lxebr");
310     }
311     
312     static void emu_madb (int rx, __u64 val, int mask) {
313             display_emulation_not_implemented("madb");
314     }
315     
316     static void emu_madbr (int rx, int ry, int mask) {
317             display_emulation_not_implemented("madbr");
318     }
319     
320     static void emu_maeb (int rx, __u32 val, int mask) {
321             display_emulation_not_implemented("maeb");
322     }
323     
324     static void emu_maebr (int rx, int ry, int mask) {
325             display_emulation_not_implemented("maebr");
326     }
327     
328     static void emu_mdb (int rx, __u64 val) {
329             current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,val);
330             set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
331     }
332     
333     static void emu_mdbr (int rx, int ry) {
334             current->thread.fp_regs.fprs[rx].d = __muldf3(current->thread.fp_regs.fprs[rx].d,
335                                              current->thread.fp_regs.fprs[ry].d);
336             set_CC_df(current->thread.fp_regs.fprs[rx].d,0ULL);
337     }
338     
339     static void emu_mdeb (int rx, __u32 val) {
340             display_emulation_not_implemented("mdeb");
341     }
342     
343     static void emu_mdebr (int rx, int ry) {
344             display_emulation_not_implemented("mdebr");
345     }
346     
347     static void emu_meeb (int rx, __u32 val) {
348             current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
349                                              val);
350             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
351     }
352     
353     static void emu_meebr (int rx, int ry) {
354             current->thread.fp_regs.fprs[rx].f = __mulsf3(current->thread.fp_regs.fprs[rx].f,
355                                              current->thread.fp_regs.fprs[ry].f);
356             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
357     }
358     
359     static void emu_msdb (int rx, __u64 val, int mask) {
360             display_emulation_not_implemented("msdb");
361     }
362     
363     static void emu_msdbr (int rx, int ry, int mask) {
364             display_emulation_not_implemented("msdbr");
365     }
366     
367     static void emu_mseb (int rx, __u32 val, int mask) {
368             display_emulation_not_implemented("mseb");
369     }
370     
371     static void emu_msebr (int rx, int ry, int mask) {
372             display_emulation_not_implemented("msebr");
373     }
374     
375     static void emu_mxbr (int rx, int ry) {
376             display_emulation_not_implemented("mxbr");
377     }
378     
379     static void emu_mxdb (int rx, __u64 val) {
380             display_emulation_not_implemented("mxdb");
381     }
382     
383     static void emu_mxdbr (int rx, int ry) {
384             display_emulation_not_implemented("mxdbr");
385     }
386     
387     static void emu_sdb (int rx, __u64 val) {
388             current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
389                                              val);
390             set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
391     }
392     
393     static void emu_sdbr (int rx, int ry) {
394             current->thread.fp_regs.fprs[rx].d = __subdf3(current->thread.fp_regs.fprs[rx].d,
395                                              current->thread.fp_regs.fprs[ry].d);
396             set_CC_sf(current->thread.fp_regs.fprs[rx].d,0ULL);
397     }
398     
399     static void emu_seb (int rx, __u32 val) {
400             current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
401                                              val);
402             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
403     }
404     
405     static void emu_sebr (int rx, int ry) {
406             current->thread.fp_regs.fprs[rx].f = __subsf3(current->thread.fp_regs.fprs[rx].f,
407                                              current->thread.fp_regs.fprs[ry].f);
408             set_CC_sf(current->thread.fp_regs.fprs[rx].f,0);
409     }
410     
411     static void emu_sfpc (int rx, int ry) {
412             display_emulation_not_implemented("sfpc");
413     }
414     
415     static void emu_sqdb (int rx, __u64 val) {
416             display_emulation_not_implemented("sqdb");
417     }
418     
419     static void emu_sqdbr (int rx, int ry) {
420             display_emulation_not_implemented("sqdbr");
421     }
422     
423     static void emu_sqeb (int rx, __u32 val) {
424             display_emulation_not_implemented("sqeb");
425     }
426     
427     static void emu_sqebr (int rx, int ry) {
428             display_emulation_not_implemented("sqebr");
429     }
430     
431     static void emu_sqxbr (int rx, int ry) {
432             display_emulation_not_implemented("sqxbr");
433     }
434     
435     static void emu_sxbr (int rx, int ry) {
436             display_emulation_not_implemented("sxbr");
437     }
438     
439     static void emu_tcdb (int rx, __u64 val) {
440             display_emulation_not_implemented("tcdb");
441     }
442     
443     static void emu_tceb (int rx, __u32 val) {
444             display_emulation_not_implemented("tceb");
445     }
446     
447     static void emu_tcxb (int rx, __u64 val) {
448             display_emulation_not_implemented("tcxb");
449     }
450     
451     
452     static inline void emu_load_regd(int reg) {
453             if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
454                     __asm__ __volatile (       /* load reg from fp_regs.fprs[reg] */
455                             "     bras  1,0f\n"
456                             "     ld    0,0(%1)\n"
457                             "0:   ex    %0,0(1)"
458                             : /* no output */
459                             : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
460                             : "1" );
461             }
462     }
463     
464     static inline void emu_load_rege(int reg) {
465             if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
466                     __asm__ __volatile (       /* load reg from fp_regs.fprs[reg] */
467                             "     bras  1,0f\n"
468                             "     le    0,0(%1)\n"
469                             "0:   ex    %0,0(1)"
470                             : /* no output */
471                             : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
472                             : "1" );
473             }
474     }
475     
476     static inline void emu_store_regd(int reg) {
477             if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
478                     __asm__ __volatile (       /* store reg to fp_regs.fprs[reg] */
479                             "     bras  1,0f\n"
480                             "     std   0,0(%1)\n"
481                             "0:   ex    %0,0(1)"
482                             : /* no output */
483                             : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].d)
484                             : "1" );
485             }
486     }
487     
488     
489     static inline void emu_store_rege(int reg) {
490             if ((reg&9) == 0) {                /* test if reg in {0,2,4,6} */
491                     __asm__ __volatile (       /* store reg to fp_regs.fprs[reg] */
492                             "     bras  1,0f\n"
493                             "     ste   0,0(%1)\n"
494                             "0:   ex    %0,0(1)"
495                             : /* no output */
496                             : "a" (reg<<4), "a" (&current->thread.fp_regs.fprs[reg].f)
497                             : "1" );
498             }
499     }
500     
501     int math_emu_b3(__u8 *opcode, struct pt_regs * regs) {
502             static const __u8 format_table[] = {
503                     2, 2, 2, 2, 9, 1, 2, 1, 2, 2, 2, 2, 9, 2, 4, 4,
504                     1, 1, 1, 1, 2, 1, 1, 2, 1, 1, 1, 1, 1, 1, 3, 3,
505                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
506                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
507                     1, 1, 1, 1,10, 1, 1, 3, 1, 1, 1, 1, 1, 1, 0, 0,
508                     0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 3, 0, 0, 0, 3,
509                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
510                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
511                     0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0,
512                     0, 0, 0, 0, 5, 6, 6, 0, 7, 8, 8, 0, 0, 0, 0, 0,
513                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
514                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
515                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
516                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
517                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
518                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
519             };
520             static const void *jump_table[]= {
521                     emu_lpebr, emu_lnebr, emu_ltebr, emu_lcebr,
522                     emu_ldebr, emu_lxdbr, emu_lxebr, emu_mxdbr,
523                     emu_kebr,  emu_cebr,  emu_aebr,  emu_sebr,
524                     emu_mdebr, emu_debr,  emu_maebr, emu_msebr,
525                     emu_lpdbr, emu_lndbr, emu_ltdbr, emu_lcdbr,
526                     emu_sqebr, emu_sqdbr, emu_sqxbr, emu_meebr,
527                     emu_kdbr,  emu_cdbr,  emu_adbr,  emu_sdbr,
528                     emu_mdbr,  emu_ddbr,  emu_madbr, emu_msdbr,
529                     NULL,      NULL,      NULL,      NULL,
530                     NULL,      NULL,      NULL,      NULL,
531                     NULL,      NULL,      NULL,      NULL,
532                     NULL,      NULL,      NULL,      NULL,
533                     NULL,      NULL,      NULL,      NULL,
534                     NULL,      NULL,      NULL,      NULL,
535                     NULL,      NULL,      NULL,      NULL,
536                     NULL,      NULL,      NULL,      NULL,
537                     emu_lpxbr, emu_lnxbr, emu_ltxbr, emu_lcxbr,
538                     emu_ledbr, emu_ldxbr, emu_lexbr, emu_fixbr,
539                     emu_kxbr,  emu_cxbr,  emu_axbr,  emu_sxbr,
540                     emu_mxbr,  emu_dxbr,  NULL,      NULL,
541                     NULL,      NULL,      NULL,      emu_diebr,
542                     NULL,      NULL,      NULL,      emu_fiebr,
543                     NULL,      NULL,      NULL,      emu_didbr,
544                     NULL,      NULL,      NULL,      emu_fidbr,
545                     NULL,      NULL,      NULL,      NULL,
546                     NULL,      NULL,      NULL,      NULL,
547                     NULL,      NULL,      NULL,      NULL,
548                     NULL,      NULL,      NULL,      NULL,
549                     NULL,      NULL,      NULL,      NULL,
550                     NULL,      NULL,      NULL,      NULL,
551                     NULL,      NULL,      NULL,      NULL,
552                     NULL,      NULL,      NULL,      NULL,
553                     NULL,      NULL,      NULL,      NULL,
554                     emu_sfpc,  NULL,      NULL,      NULL,
555                     NULL,      NULL,      NULL,      NULL,
556                     emu_efpc,  NULL,      NULL,      NULL,
557                     NULL,      NULL,      NULL,      NULL,
558                     emu_cefbr, emu_cdfbr, emu_cxfbr, NULL,
559                     emu_cfebr, emu_cfdbr, emu_cfxbr
560             };
561     
562             switch (format_table[opcode[1]]) {
563             case 1: /* RRE format, double operation */
564                     emu_store_regd((opcode[3]>>4)&15);
565                     emu_store_regd(opcode[3]&15);
566                     /* call the emulation function */
567                     ((void (*)(int, int))jump_table[opcode[1]])
568                             (opcode[3]>>4,opcode[3]&15);
569                     emu_load_regd((opcode[3]>>4)&15);
570                     emu_load_regd(opcode[3]&15);
571                     return 0;
572             case 2: /* RRE format, float operation */
573                     emu_store_rege((opcode[3]>>4)&15);
574                     emu_store_rege(opcode[3]&15);
575                     /* call the emulation function */
576                     ((void (*)(int, int))jump_table[opcode[1]])
577                             (opcode[3]>>4,opcode[3]&15);
578                     emu_load_rege((opcode[3]>>4)&15);
579                     emu_load_rege(opcode[3]&15);
580                     return 0;
581             case 3: /* RRF format, double operation */
582                     emu_store_regd((opcode[3]>>4)&15);
583                     emu_store_regd(opcode[3]&15);
584                     /* call the emulation function */
585                     ((void (*)(int, int, int))jump_table[opcode[1]])
586                             (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
587                     emu_load_regd((opcode[3]>>4)&15);
588                     emu_load_regd(opcode[3]&15);
589                     return 0;
590             case 4: /* RRF format, float operation */
591                     emu_store_rege((opcode[3]>>4)&15);
592                     emu_store_rege(opcode[3]&15);
593                     /* call the emulation function */
594                     ((void (*)(int, int, int))jump_table[opcode[1]])
595                             (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
596                     emu_load_rege((opcode[3]>>4)&15);
597                     emu_load_rege(opcode[3]&15);
598                     return 0;
599             case 5: /* RRE format, cefbr instruction */
600                     emu_store_rege((opcode[3]>>4)&15);
601                     /* call the emulation function */
602                     ((void (*)(int, int))jump_table[opcode[1]])
603                             (opcode[3]>>4,opcode[3]&15);
604                     emu_load_rege((opcode[3]>>4)&15);
605                     return 0;
606             case 6: /* RRE format, cdfbr & cxfbr instruction */
607                     emu_store_regd((opcode[3]>>4)&15);
608                     /* call the emulation function */
609                     ((void (*)(int, int))jump_table[opcode[1]])
610                             (opcode[3]>>4,opcode[3]&15);
611                     emu_load_regd((opcode[3]>>4)&15);
612                     return 0;
613                     /* FIXME !! */
614                     return 0;
615             case 7: /* RRF format, cfebr instruction */
616                     emu_store_rege(opcode[3]&15);
617                     /* call the emulation function */
618                     ((void (*)(int, int, int))jump_table[opcode[1]])
619                             (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
620                     return 0;
621             case 8: /* RRF format, cfdbr & cfxbr instruction */
622                     emu_store_regd(opcode[3]&15);
623                     /* call the emulation function */
624                     ((void (*)(int, int, int))jump_table[opcode[1]])
625                             (opcode[3]>>4,opcode[3]&15,opcode[2]>>4);
626                     return 0;
627     	case 9: /* RRE format, ldebr & mdebr instruction */
628     		/* float store but double load */
629                     emu_store_rege((opcode[3]>>4)&15);
630                     emu_store_rege(opcode[3]&15);
631                     /* call the emulation function */
632                     ((void (*)(int, int))jump_table[opcode[1]])
633                             (opcode[3]>>4,opcode[3]&15);
634                     emu_load_regd((opcode[3]>>4)&15);
635                     return 0;
636             case 10: /* RRE format, ledbr instruction */
637     		/* double store but float load */
638                     emu_store_regd((opcode[3]>>4)&15);
639                     emu_store_regd(opcode[3]&15);
640                     /* call the emulation function */
641                     ((void (*)(int, int))jump_table[opcode[1]])
642                             (opcode[3]>>4,opcode[3]&15);
643                     emu_load_rege((opcode[3]>>4)&15);
644                     return 0;
645             default:
646                     return 1;
647             }
648     }
649     
650     static void* calc_addr(struct pt_regs *regs,int rx,int rb,int disp)
651     {
652       rx &= 0xf;
653       rb &= 0xf;
654       disp &= 0xfff;
655       return (void*) ((rx != 0 ? regs->gprs[rx] : 0)  + /* index */   
656              (rb != 0 ? regs->gprs[rb] : 0)  + /* base */
657              disp);
658     }
659         
660     int math_emu_ed(__u8 *opcode, struct pt_regs * regs) {
661             static const __u8 format_table[] = {
662                     0, 0, 0, 0, 5, 1, 2, 1, 2, 2, 2, 2, 5, 2, 4, 4,
663                     2, 1, 1, 0, 2, 1, 0, 2, 1, 1, 1, 1, 1, 1, 3, 3,
664                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
665                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
666                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
667                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
668                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
669                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
670                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
671                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
672                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
673                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
674                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
675                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
676                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
677                     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
678             };
679             static const void *jump_table[]= {
680                     NULL,     NULL,     NULL,     NULL,
681                     emu_ldeb, emu_lxdb, emu_lxeb, emu_mxdb,
682                     emu_keb,  emu_ceb,  emu_aeb,  emu_seb,
683                     emu_mdeb, emu_deb,  emu_maeb, emu_mseb,
684                     emu_tceb, emu_tcdb, emu_tcxb, NULL,
685                     emu_sqeb, emu_sqdb, NULL,     emu_meeb,
686                     emu_kdb,  emu_cdb,  emu_adb,  emu_sdb,
687                     emu_mdb,  emu_ddb,  emu_madb, emu_msdb
688             };
689     
690             switch (format_table[opcode[5]]) {
691             case 1: /* RXE format, __u64 constant */ {
692                     __u64 *dxb, temp;
693                     __u32 opc;
694     
695                     emu_store_regd((opcode[1]>>4)&15);
696                     opc = *((__u32 *) opcode);
697                     dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
698                     /* FIXME: how to react if copy_from_user fails ? */
699                     copy_from_user(&temp, dxb, 8);
700                     /* call the emulation function */
701                     ((void (*)(int, __u64))jump_table[opcode[5]])
702                             (opcode[1]>>4,temp);
703                     emu_load_regd((opcode[1]>>4)&15);
704                     return 0;
705             }
706             case 2: /* RXE format, __u32 constant */ {
707                     __u32 *dxb, temp;
708                     __u32 opc;
709     
710                     emu_store_rege((opcode[1]>>4)&15);
711                     opc = *((__u32 *) opcode);
712                     dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
713                     /* FIXME: how to react if get_user fails ? */
714                     get_user(temp, dxb);
715                     /* call the emulation function */
716                     ((void (*)(int, __u32))jump_table[opcode[5]])
717                             (opcode[1]>>4,temp);
718                     emu_load_rege((opcode[1]>>4)&15);
719                     return 0;
720             }
721             case 3: /* RXF format, __u64 constant */ {
722                     __u32 *dxb, temp;
723                     __u32 opc;
724     
725                     emu_store_regd((opcode[1]>>4)&15);
726                     opc = *((__u32 *) opcode);
727                     dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
728                     /* FIXME: how to react if copy_from_user fails ? */
729                     copy_from_user(&temp, dxb, 8);
730                     /* call the emulation function */
731                     ((void (*)(int, __u32, int))jump_table[opcode[5]])
732                             (opcode[1]>>4,temp,opcode[4]>>4);
733                     emu_load_regd((opcode[1]>>4)&15);
734                     return 0;
735             }
736             case 4: /* RXF format, __u32 constant */ {
737                     __u32 *dxb, temp;
738                     __u32 opc;
739     
740                     emu_store_rege((opcode[1]>>4)&15);
741                     opc = *((__u32 *) opcode);
742                     dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
743                     /* FIXME: how to react if get_user fails ? */
744                     get_user(temp, dxb);
745                     /* call the emulation function */
746                     ((void (*)(int, __u32, int))jump_table[opcode[5]])
747                             (opcode[1]>>4,temp,opcode[4]>>4);
748                     emu_load_rege((opcode[1]>>4)&15);
749                     return 0;
750             }
751     	case 5: /* RXE format, __u32 constant */
752                     /* store_rege and load_regd */ 
753     		{
754                     __u32 *dxb, temp;
755                     __u32 opc;
756                     emu_store_rege((opcode[1]>>4)&15);
757                     opc = *((__u32 *) opcode);
758                     dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
759                     /* FIXME: how to react if get_user fails ? */
760                     get_user(temp, dxb);
761                     /* call the emulation function */
762                     ((void (*)(int, __u32))jump_table[opcode[5]])
763                             (opcode[1]>>4,temp);
764                     emu_load_regd((opcode[1]>>4)&15);
765                     return 0;
766             }
767             default:
768                     return 1;
769             }
770     }
771     
772     /*
773      * Emulate LDR Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
774      */
775     void math_emu_ldr(__u8 *opcode) {
776             __u16 opc = *((__u16 *) opcode);
777     
778             if ((opc & 0x0090) == 0) {         /* test if rx in {0,2,4,6} */
779                     /* we got an exception therfore ry can't be in {0,2,4,6} */
780                     __asm__ __volatile (       /* load rx from fp_regs.fprs[ry] */
781                             "     bras  1,0f\n"
782                             "     ld    0,0(%1)\n"
783                             "0:   ex    %0,0(1)"
784                             : /* no output */
785                             : "a" (opc&0x00f0),
786                               "a" (&current->thread.fp_regs.fprs[opc&0x000f].d)
787                             : "1" );
788             } else if ((opc & 0x0009) == 0) {  /* test if ry in {0,2,4,6} */
789                     __asm__ __volatile (       /* store ry to fp_regs.fprs[rx] */
790                             "     bras  1,0f\n"
791                             "     std   0,0(%1)\n"
792                             "0:   ex    %0,0(1)"
793                             : /* no output */
794                             : "a" ((opc&0x000f)<<4),
795                               "a" (&current->thread.fp_regs.fprs[(opc&0x00f0)>>4].d)
796                             : "1" );
797             } else {                          /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
798                     current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
799                             current->thread.fp_regs.fprs[opc&0x000f];
800             }
801     }
802     
803     /*
804      * Emulate LER Rx,Ry with Rx or Ry not in {0, 2, 4, 6}
805      */
806     void math_emu_ler(__u8 *opcode) {
807             __u16 opc = *((__u16 *) opcode);
808     
809             if ((opc & 0x0090) == 0) {         /* test if rx in {0,2,4,6} */
810                     /* we got an exception therfore ry can't be in {0,2,4,6} */
811                     __asm__ __volatile (       /* load rx from fp_regs.fprs[ry] */
812                             "     bras  1,0f\n"
813                             "     le    0,0(%1)\n"
814                             "0:   ex    %0,0(1)"
815                             : /* no output */
816                             : "a" (opc&0x00f0),
817                               "a" (&current->thread.fp_regs.fprs[opc&0x000f].f)
818                             : "1" );
819             } else if ((opc & 0x0009) == 0) {  /* test if ry in {0,2,4,6} */
820                     __asm__ __volatile (       /* store ry to fp_regs.fprs[rx] */
821                             "     bras  1,0f\n"
822                             "     ste   0,0(%1)\n"
823                             "0:   ex    %0,0(1)"
824                             : /* no output */
825                             : "a" ((opc&0x000f)<<4),
826                               "a" (&current->thread.fp_regs.fprs[(opc&0x00f0)>>4].f)
827                             : "1" );
828             } else {                          /* move fp_regs.fprs[ry] to fp_regs.fprs[rx] */
829                     current->thread.fp_regs.fprs[(opc&0x00f0)>>4] =
830                             current->thread.fp_regs.fprs[opc&0x000f];
831             }
832     }
833     
834     /*
835      * Emulate LD R,D(X,B) with R not in {0, 2, 4, 6}
836      */
837     void math_emu_ld(__u8 *opcode, struct pt_regs * regs) {
838             __u32 opc = *((__u32 *) opcode);
839             __u64 *dxb;
840     
841             dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
842             /* FIXME: how to react if copy_from_user fails ? */
843             copy_from_user(&current->thread.fp_regs.fprs[(opc>>20)&15].d, dxb, 8);
844     }
845     
846     /*
847      * Emulate LE R,D(X,B) with R not in {0, 2, 4, 6}
848      */
849     void math_emu_le(__u8 *opcode, struct pt_regs * regs) {
850             __u32 opc = *((__u32 *) opcode);
851             __u32 *mem, *dxb;
852     
853             dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
854             /* FIXME: how to react if get_user fails ? */
855             mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
856             get_user(mem[0], dxb);
857     }
858     
859     /*
860      * Emulate STD R,D(X,B) with R not in {0, 2, 4, 6}
861      */
862     void math_emu_std(__u8 *opcode, struct pt_regs * regs) {
863             __u32 opc = *((__u32 *) opcode);
864             __u64 *dxb;
865             dxb = (__u64 *) calc_addr(regs,opc>>16,opc>>12,opc);
866             /* FIXME: how to react if copy_to_user fails ? */
867             copy_to_user(dxb, &current->thread.fp_regs.fprs[(opc>>20)&15].d, 8);
868     }
869     
870     /*
871      * Emulate STE R,D(X,B) with R not in {0, 2, 4, 6}
872      */
873     void math_emu_ste(__u8 *opcode, struct pt_regs * regs) {
874             __u32 opc = *((__u32 *) opcode);
875             __u32 *mem, *dxb;
876             dxb = (__u32 *) calc_addr(regs,opc>>16,opc>>12,opc);
877             /* FIXME: how to react if put_user fails ? */
878             mem = (__u32 *) (&current->thread.fp_regs.fprs[(opc>>20)&15].f);
879             put_user(mem[0], dxb);
880     }
881     
882     /*
883      * Emulate LFPC D(B)
884      */
885     int math_emu_lfpc(__u8 *opcode, struct pt_regs *regs) {
886             /* FIXME: how to do that ?!? */
887             return 0;
888     }
889     
890     /*
891      * Emulate STFPC D(B)
892      */
893     int math_emu_stfpc(__u8 *opcode, struct pt_regs *regs) {
894             /* FIXME: how to do that ?!? */
895             return 0;
896     }
897     
898     /*
899      * Emulate SRNM D(B)
900      */
901     int math_emu_srnm(__u8 *opcode, struct pt_regs *regs) {
902             /* FIXME: how to do that ?!? */
903             return 0;
904     }
905     
906     
907     
908     
909     
910     
911     
912     
913     
914     
915     
916     
917     
918     
919     
920     
921