1
2
3
4
5
6
7
8
9#include <linux/init.h>
10#include <linux/kernel.h>
11#include <linux/ptrace.h>
12#include <linux/stddef.h>
13
14#include <asm/bugs.h>
15#include <asm/compiler.h>
16#include <asm/cpu.h>
17#include <asm/fpu.h>
18#include <asm/mipsregs.h>
19#include <asm/system.h>
20
21static char bug64hit[] __initdata =
22 "reliable operation impossible!\n%s";
23static char nowar[] __initdata =
24 "Please report to <linux-mips@linux-mips.org>.";
25static char r4kwar[] __initdata =
26 "Enable CPU_R4000_WORKAROUNDS to rectify.";
27static char daddiwar[] __initdata =
28 "Enable CPU_DADDI_WORKAROUNDS to rectify.";
29
30static inline void align_mod(const int align, const int mod)
31{
32 asm volatile(
33 ".set push\n\t"
34 ".set noreorder\n\t"
35 ".balign %0\n\t"
36 ".rept %1\n\t"
37 "nop\n\t"
38 ".endr\n\t"
39 ".set pop"
40 :
41 : GCC_IMM_ASM() (align), GCC_IMM_ASM() (mod));
42}
43
44static inline void mult_sh_align_mod(long *v1, long *v2, long *w,
45 const int align, const int mod)
46{
47 unsigned long flags;
48 int m1, m2;
49 long p, s, lv1, lv2, lw;
50
51
52
53
54
55
56
57
58
59 local_irq_save(flags);
60
61
62
63
64
65
66
67
68
69
70 asm volatile(
71 ""
72 : "=r" (m1), "=r" (m2), "=r" (s)
73 : "0" (5), "1" (8), "2" (5));
74 align_mod(align, mod);
75
76
77
78
79
80
81 asm volatile(
82 ".set push\n\t"
83 ".set noat\n\t"
84 ".set noreorder\n\t"
85 ".set nomacro\n\t"
86 "mult %2, %3\n\t"
87 "dsll32 %0, %4, %5\n\t"
88 "mflo $0\n\t"
89 "dsll32 %1, %4, %5\n\t"
90 "nop\n\t"
91 ".set pop"
92 : "=&r" (lv1), "=r" (lw)
93 : "r" (m1), "r" (m2), "r" (s), "I" (0)
94 : "hi", "lo", GCC_REG_ACCUM);
95
96
97
98
99
100
101 asm volatile(
102 ""
103 : "=r" (m1), "=r" (m2), "=r" (s)
104 : "0" (m1), "1" (m2), "2" (s));
105 align_mod(align, mod);
106 p = m1 * m2;
107 lv2 = s << 32;
108 asm volatile(
109 ""
110 : "=r" (lv2)
111 : "0" (lv2), "r" (p));
112 local_irq_restore(flags);
113
114 *v1 = lv1;
115 *v2 = lv2;
116 *w = lw;
117}
118
119static inline void check_mult_sh(void)
120{
121 long v1[8], v2[8], w[8];
122 int bug, fix, i;
123
124 printk("Checking for the multiply/shift bug... ");
125
126
127
128
129
130
131
132
133
134
135 mult_sh_align_mod(&v1[0], &v2[0], &w[0], 32, 0);
136 mult_sh_align_mod(&v1[1], &v2[1], &w[1], 32, 1);
137 mult_sh_align_mod(&v1[2], &v2[2], &w[2], 32, 2);
138 mult_sh_align_mod(&v1[3], &v2[3], &w[3], 32, 3);
139 mult_sh_align_mod(&v1[4], &v2[4], &w[4], 32, 4);
140 mult_sh_align_mod(&v1[5], &v2[5], &w[5], 32, 5);
141 mult_sh_align_mod(&v1[6], &v2[6], &w[6], 32, 6);
142 mult_sh_align_mod(&v1[7], &v2[7], &w[7], 32, 7);
143
144 bug = 0;
145 for (i = 0; i < 8; i++)
146 if (v1[i] != w[i])
147 bug = 1;
148
149 if (bug == 0) {
150 printk("no.\n");
151 return;
152 }
153
154 printk("yes, workaround... ");
155
156 fix = 1;
157 for (i = 0; i < 8; i++)
158 if (v2[i] != w[i])
159 fix = 0;
160
161 if (fix == 1) {
162 printk("yes.\n");
163 return;
164 }
165
166 printk("no.\n");
167 panic(bug64hit, !R4000_WAR ? r4kwar : nowar);
168}
169
170static volatile int daddi_ov __cpuinitdata = 0;
171
172asmlinkage void __init do_daddi_ov(struct pt_regs *regs)
173{
174 daddi_ov = 1;
175 regs->cp0_epc += 4;
176}
177
178static inline void check_daddi(void)
179{
180 extern asmlinkage void handle_daddi_ov(void);
181 unsigned long flags;
182 void *handler;
183 long v, tmp;
184
185 printk("Checking for the daddi bug... ");
186
187 local_irq_save(flags);
188 handler = set_except_vector(12, handle_daddi_ov);
189
190
191
192
193
194
195
196
197
198 asm volatile(
199 ".set push\n\t"
200 ".set noat\n\t"
201 ".set noreorder\n\t"
202 ".set nomacro\n\t"
203 "addiu %1, $0, %2\n\t"
204 "dsrl %1, %1, 1\n\t"
205#ifdef HAVE_AS_SET_DADDI
206 ".set daddi\n\t"
207#endif
208 "daddi %0, %1, %3\n\t"
209 ".set pop"
210 : "=r" (v), "=&r" (tmp)
211 : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
212 set_except_vector(12, handler);
213 local_irq_restore(flags);
214
215 if (daddi_ov) {
216 printk("no.\n");
217 return;
218 }
219
220 printk("yes, workaround... ");
221
222 local_irq_save(flags);
223 handler = set_except_vector(12, handle_daddi_ov);
224 asm volatile(
225 "addiu %1, $0, %2\n\t"
226 "dsrl %1, %1, 1\n\t"
227 "daddi %0, %1, %3"
228 : "=r" (v), "=&r" (tmp)
229 : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
230 set_except_vector(12, handler);
231 local_irq_restore(flags);
232
233 if (daddi_ov) {
234 printk("yes.\n");
235 return;
236 }
237
238 printk("no.\n");
239 panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
240}
241
242int daddiu_bug __cpuinitdata = -1;
243
244static inline void check_daddiu(void)
245{
246 long v, w, tmp;
247
248 printk("Checking for the daddiu bug... ");
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266 asm volatile(
267 ".set push\n\t"
268 ".set noat\n\t"
269 ".set noreorder\n\t"
270 ".set nomacro\n\t"
271 "addiu %2, $0, %3\n\t"
272 "dsrl %2, %2, 1\n\t"
273#ifdef HAVE_AS_SET_DADDI
274 ".set daddi\n\t"
275#endif
276 "daddiu %0, %2, %4\n\t"
277 "addiu %1, $0, %4\n\t"
278 "daddu %1, %2\n\t"
279 ".set pop"
280 : "=&r" (v), "=&r" (w), "=&r" (tmp)
281 : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
282
283 daddiu_bug = v != w;
284
285 if (!daddiu_bug) {
286 printk("no.\n");
287 return;
288 }
289
290 printk("yes, workaround... ");
291
292 asm volatile(
293 "addiu %2, $0, %3\n\t"
294 "dsrl %2, %2, 1\n\t"
295 "daddiu %0, %2, %4\n\t"
296 "addiu %1, $0, %4\n\t"
297 "daddu %1, %2"
298 : "=&r" (v), "=&r" (w), "=&r" (tmp)
299 : "I" (0xffffffffffffdb9aUL), "I" (0x1234));
300
301 if (v == w) {
302 printk("yes.\n");
303 return;
304 }
305
306 printk("no.\n");
307 panic(bug64hit, !DADDI_WAR ? daddiwar : nowar);
308}
309
310void __init check_bugs64_early(void)
311{
312 check_mult_sh();
313 check_daddiu();
314}
315
316void __init check_bugs64(void)
317{
318 check_daddi();
319}
320