1#include <linux/compiler.h>
2#include <linux/mm.h>
3#include <linux/signal.h>
4#include <linux/smp.h>
5
6#include <asm/asm.h>
7#include <asm/bootinfo.h>
8#include <asm/byteorder.h>
9#include <asm/cpu.h>
10#include <asm/inst.h>
11#include <asm/processor.h>
12#include <asm/uaccess.h>
13#include <asm/branch.h>
14#include <asm/mipsregs.h>
15#include <asm/system.h>
16#include <asm/cacheflush.h>
17
18#include <asm/fpu_emulator.h>
19
20#include "ieee754.h"
21
22
23
24#ifdef __mips
25#undef __mips
26#endif
27#define __mips 4
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46struct emuframe {
47 mips_instruction emul;
48 mips_instruction badinst;
49 mips_instruction cookie;
50 unsigned long epc;
51};
52
53int mips_dsemul(struct pt_regs *regs, mips_instruction ir, unsigned long cpc)
54{
55 extern asmlinkage void handle_dsemulret(void);
56 struct emuframe __user *fr;
57 int err;
58
59 if (ir == 0) {
60 regs->cp0_epc = cpc;
61 regs->cp0_cause &= ~CAUSEF_BD;
62 return 0;
63 }
64#ifdef DSEMUL_TRACE
65 printk("dsemul %lx %lx\n", regs->cp0_epc, cpc);
66
67#endif
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88 fr = (struct emuframe __user *)
89 ((regs->regs[29] - sizeof(struct emuframe)) & ~0x7);
90
91
92 if (unlikely(!access_ok(VERIFY_WRITE, fr, sizeof(struct emuframe))))
93 return SIGBUS;
94
95 err = __put_user(ir, &fr->emul);
96 err |= __put_user((mips_instruction)BREAK_MATH, &fr->badinst);
97 err |= __put_user((mips_instruction)BD_COOKIE, &fr->cookie);
98 err |= __put_user(cpc, &fr->epc);
99
100 if (unlikely(err)) {
101 MIPS_FPU_EMU_INC_STATS(errors);
102 return SIGBUS;
103 }
104
105 regs->cp0_epc = (unsigned long) &fr->emul;
106
107 flush_cache_sigtramp((unsigned long)&fr->badinst);
108
109 return SIGILL;
110}
111
112int do_dsemulret(struct pt_regs *xcp)
113{
114 struct emuframe __user *fr;
115 unsigned long epc;
116 u32 insn, cookie;
117 int err = 0;
118
119 fr = (struct emuframe __user *)
120 (xcp->cp0_epc - sizeof(mips_instruction));
121
122
123
124
125
126 if (!access_ok(VERIFY_READ, fr, sizeof(struct emuframe)))
127 return 0;
128
129
130
131
132
133
134
135 err = __get_user(insn, &fr->badinst);
136 err |= __get_user(cookie, &fr->cookie);
137
138 if (unlikely(err || (insn != BREAK_MATH) || (cookie != BD_COOKIE))) {
139 MIPS_FPU_EMU_INC_STATS(errors);
140 return 0;
141 }
142
143
144
145
146
147
148
149
150
151
152
153#ifdef DSEMUL_TRACE
154 printk("dsemulret\n");
155#endif
156 if (__get_user(epc, &fr->epc)) {
157
158 force_sig(SIGBUS, current);
159
160 return 0;
161 }
162
163
164 xcp->cp0_epc = epc;
165
166 return 1;
167}
168