Commit | Line | Data |
---|---|---|
14cf11af PM |
1 | /* |
2 | * Single-step support. | |
3 | * | |
4 | * Copyright (C) 2004 Paul Mackerras <paulus@au.ibm.com>, IBM | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version | |
9 | * 2 of the License, or (at your option) any later version. | |
10 | */ | |
11 | #include <linux/kernel.h> | |
0d69a052 | 12 | #include <linux/kprobes.h> |
14cf11af | 13 | #include <linux/ptrace.h> |
268bb0ce | 14 | #include <linux/prefetch.h> |
14cf11af PM |
15 | #include <asm/sstep.h> |
16 | #include <asm/processor.h> | |
7c0f6ba6 | 17 | #include <linux/uaccess.h> |
5e9d0e3d | 18 | #include <asm/cpu_has_feature.h> |
0016a4cf | 19 | #include <asm/cputable.h> |
14cf11af PM |
20 | |
21 | extern char system_call_common[]; | |
22 | ||
c032524f | 23 | #ifdef CONFIG_PPC64 |
14cf11af | 24 | /* Bits in SRR1 that are copied from MSR */ |
af308377 | 25 | #define MSR_MASK 0xffffffff87c0ffffUL |
c032524f PM |
26 | #else |
27 | #define MSR_MASK 0x87c0ffff | |
28 | #endif | |
14cf11af | 29 | |
0016a4cf PM |
30 | /* Bits in XER */ |
31 | #define XER_SO 0x80000000U | |
32 | #define XER_OV 0x40000000U | |
33 | #define XER_CA 0x20000000U | |
924c8feb SD |
34 | #define XER_OV32 0x00080000U |
35 | #define XER_CA32 0x00040000U | |
0016a4cf | 36 | |
cd64d169 | 37 | #ifdef CONFIG_PPC_FPU |
0016a4cf PM |
38 | /* |
39 | * Functions in ldstfp.S | |
40 | */ | |
c22435a5 PM |
41 | extern void get_fpr(int rn, double *p); |
42 | extern void put_fpr(int rn, const double *p); | |
43 | extern void get_vr(int rn, __vector128 *p); | |
44 | extern void put_vr(int rn, __vector128 *p); | |
350779a2 PM |
45 | extern void load_vsrn(int vsr, const void *p); |
46 | extern void store_vsrn(int vsr, void *p); | |
47 | extern void conv_sp_to_dp(const float *sp, double *dp); | |
48 | extern void conv_dp_to_sp(const double *dp, float *sp); | |
49 | #endif | |
50 | ||
51 | #ifdef __powerpc64__ | |
52 | /* | |
53 | * Functions in quad.S | |
54 | */ | |
55 | extern int do_lq(unsigned long ea, unsigned long *regs); | |
56 | extern int do_stq(unsigned long ea, unsigned long val0, unsigned long val1); | |
57 | extern int do_lqarx(unsigned long ea, unsigned long *regs); | |
58 | extern int do_stqcx(unsigned long ea, unsigned long val0, unsigned long val1, | |
59 | unsigned int *crp); | |
60 | #endif | |
61 | ||
62 | #ifdef __LITTLE_ENDIAN__ | |
63 | #define IS_LE 1 | |
64 | #define IS_BE 0 | |
65 | #else | |
66 | #define IS_LE 0 | |
67 | #define IS_BE 1 | |
cd64d169 | 68 | #endif |
0016a4cf | 69 | |
b91e136c ME |
70 | /* |
71 | * Emulate the truncation of 64 bit values in 32-bit mode. | |
72 | */ | |
71f6e58e NR |
73 | static nokprobe_inline unsigned long truncate_if_32bit(unsigned long msr, |
74 | unsigned long val) | |
b91e136c ME |
75 | { |
76 | #ifdef __powerpc64__ | |
77 | if ((msr & MSR_64BIT) == 0) | |
78 | val &= 0xffffffffUL; | |
79 | #endif | |
80 | return val; | |
81 | } | |
82 | ||
14cf11af PM |
83 | /* |
84 | * Determine whether a conditional branch instruction would branch. | |
85 | */ | |
3cdfcbfd PM |
86 | static nokprobe_inline int branch_taken(unsigned int instr, |
87 | const struct pt_regs *regs, | |
88 | struct instruction_op *op) | |
14cf11af PM |
89 | { |
90 | unsigned int bo = (instr >> 21) & 0x1f; | |
91 | unsigned int bi; | |
92 | ||
93 | if ((bo & 4) == 0) { | |
94 | /* decrement counter */ | |
3cdfcbfd PM |
95 | op->type |= DECCTR; |
96 | if (((bo >> 1) & 1) ^ (regs->ctr == 1)) | |
14cf11af PM |
97 | return 0; |
98 | } | |
99 | if ((bo & 0x10) == 0) { | |
100 | /* check bit from CR */ | |
101 | bi = (instr >> 16) & 0x1f; | |
102 | if (((regs->ccr >> (31 - bi)) & 1) != ((bo >> 3) & 1)) | |
103 | return 0; | |
104 | } | |
105 | return 1; | |
106 | } | |
107 | ||
b9da9c8a PM |
108 | static nokprobe_inline long address_ok(struct pt_regs *regs, |
109 | unsigned long ea, int nb) | |
0016a4cf PM |
110 | { |
111 | if (!user_mode(regs)) | |
112 | return 1; | |
b9da9c8a PM |
113 | if (__access_ok(ea, nb, USER_DS)) |
114 | return 1; | |
115 | if (__access_ok(ea, 1, USER_DS)) | |
116 | /* Access overlaps the end of the user region */ | |
117 | regs->dar = USER_DS.seg; | |
118 | else | |
119 | regs->dar = ea; | |
120 | return 0; | |
0016a4cf PM |
121 | } |
122 | ||
123 | /* | |
124 | * Calculate effective address for a D-form instruction | |
125 | */ | |
3cdfcbfd PM |
126 | static nokprobe_inline unsigned long dform_ea(unsigned int instr, |
127 | const struct pt_regs *regs) | |
0016a4cf PM |
128 | { |
129 | int ra; | |
130 | unsigned long ea; | |
131 | ||
132 | ra = (instr >> 16) & 0x1f; | |
133 | ea = (signed short) instr; /* sign-extend */ | |
be96f633 | 134 | if (ra) |
0016a4cf | 135 | ea += regs->gpr[ra]; |
b91e136c | 136 | |
d120cdbc | 137 | return ea; |
0016a4cf PM |
138 | } |
139 | ||
140 | #ifdef __powerpc64__ | |
141 | /* | |
142 | * Calculate effective address for a DS-form instruction | |
143 | */ | |
3cdfcbfd PM |
144 | static nokprobe_inline unsigned long dsform_ea(unsigned int instr, |
145 | const struct pt_regs *regs) | |
0016a4cf PM |
146 | { |
147 | int ra; | |
148 | unsigned long ea; | |
149 | ||
150 | ra = (instr >> 16) & 0x1f; | |
151 | ea = (signed short) (instr & ~3); /* sign-extend */ | |
be96f633 | 152 | if (ra) |
0016a4cf | 153 | ea += regs->gpr[ra]; |
b91e136c | 154 | |
d120cdbc | 155 | return ea; |
0016a4cf | 156 | } |
350779a2 PM |
157 | |
158 | /* | |
159 | * Calculate effective address for a DQ-form instruction | |
160 | */ | |
161 | static nokprobe_inline unsigned long dqform_ea(unsigned int instr, | |
162 | const struct pt_regs *regs) | |
163 | { | |
164 | int ra; | |
165 | unsigned long ea; | |
166 | ||
167 | ra = (instr >> 16) & 0x1f; | |
168 | ea = (signed short) (instr & ~0xf); /* sign-extend */ | |
169 | if (ra) | |
170 | ea += regs->gpr[ra]; | |
171 | ||
d120cdbc | 172 | return ea; |
350779a2 | 173 | } |
0016a4cf PM |
174 | #endif /* __powerpc64 */ |
175 | ||
176 | /* | |
177 | * Calculate effective address for an X-form instruction | |
178 | */ | |
71f6e58e | 179 | static nokprobe_inline unsigned long xform_ea(unsigned int instr, |
3cdfcbfd | 180 | const struct pt_regs *regs) |
0016a4cf PM |
181 | { |
182 | int ra, rb; | |
183 | unsigned long ea; | |
184 | ||
185 | ra = (instr >> 16) & 0x1f; | |
186 | rb = (instr >> 11) & 0x1f; | |
187 | ea = regs->gpr[rb]; | |
be96f633 | 188 | if (ra) |
0016a4cf | 189 | ea += regs->gpr[ra]; |
b91e136c | 190 | |
d120cdbc | 191 | return ea; |
0016a4cf PM |
192 | } |
193 | ||
194 | /* | |
195 | * Return the largest power of 2, not greater than sizeof(unsigned long), | |
196 | * such that x is a multiple of it. | |
197 | */ | |
71f6e58e | 198 | static nokprobe_inline unsigned long max_align(unsigned long x) |
0016a4cf PM |
199 | { |
200 | x |= sizeof(unsigned long); | |
201 | return x & -x; /* isolates rightmost bit */ | |
202 | } | |
203 | ||
71f6e58e | 204 | static nokprobe_inline unsigned long byterev_2(unsigned long x) |
0016a4cf PM |
205 | { |
206 | return ((x >> 8) & 0xff) | ((x & 0xff) << 8); | |
207 | } | |
208 | ||
71f6e58e | 209 | static nokprobe_inline unsigned long byterev_4(unsigned long x) |
0016a4cf PM |
210 | { |
211 | return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) | | |
212 | ((x & 0xff00) << 8) | ((x & 0xff) << 24); | |
213 | } | |
214 | ||
215 | #ifdef __powerpc64__ | |
71f6e58e | 216 | static nokprobe_inline unsigned long byterev_8(unsigned long x) |
0016a4cf PM |
217 | { |
218 | return (byterev_4(x) << 32) | byterev_4(x >> 32); | |
219 | } | |
220 | #endif | |
221 | ||
d955189a PM |
222 | static nokprobe_inline void do_byte_reverse(void *ptr, int nb) |
223 | { | |
224 | switch (nb) { | |
225 | case 2: | |
226 | *(u16 *)ptr = byterev_2(*(u16 *)ptr); | |
227 | break; | |
228 | case 4: | |
229 | *(u32 *)ptr = byterev_4(*(u32 *)ptr); | |
230 | break; | |
231 | #ifdef __powerpc64__ | |
232 | case 8: | |
233 | *(unsigned long *)ptr = byterev_8(*(unsigned long *)ptr); | |
234 | break; | |
235 | case 16: { | |
236 | unsigned long *up = (unsigned long *)ptr; | |
237 | unsigned long tmp; | |
238 | tmp = byterev_8(up[0]); | |
239 | up[0] = byterev_8(up[1]); | |
240 | up[1] = tmp; | |
241 | break; | |
242 | } | |
243 | #endif | |
244 | default: | |
245 | WARN_ON_ONCE(1); | |
246 | } | |
247 | } | |
248 | ||
71f6e58e | 249 | static nokprobe_inline int read_mem_aligned(unsigned long *dest, |
b9da9c8a PM |
250 | unsigned long ea, int nb, |
251 | struct pt_regs *regs) | |
0016a4cf PM |
252 | { |
253 | int err = 0; | |
254 | unsigned long x = 0; | |
255 | ||
256 | switch (nb) { | |
257 | case 1: | |
258 | err = __get_user(x, (unsigned char __user *) ea); | |
259 | break; | |
260 | case 2: | |
261 | err = __get_user(x, (unsigned short __user *) ea); | |
262 | break; | |
263 | case 4: | |
264 | err = __get_user(x, (unsigned int __user *) ea); | |
265 | break; | |
266 | #ifdef __powerpc64__ | |
267 | case 8: | |
268 | err = __get_user(x, (unsigned long __user *) ea); | |
269 | break; | |
270 | #endif | |
271 | } | |
272 | if (!err) | |
273 | *dest = x; | |
b9da9c8a PM |
274 | else |
275 | regs->dar = ea; | |
0016a4cf PM |
276 | return err; |
277 | } | |
278 | ||
e0a0986b PM |
279 | /* |
280 | * Copy from userspace to a buffer, using the largest possible | |
281 | * aligned accesses, up to sizeof(long). | |
282 | */ | |
174b701d | 283 | static nokprobe_inline int copy_mem_in(u8 *dest, unsigned long ea, int nb, |
b9da9c8a | 284 | struct pt_regs *regs) |
0016a4cf | 285 | { |
e0a0986b PM |
286 | int err = 0; |
287 | int c; | |
0016a4cf | 288 | |
0016a4cf PM |
289 | for (; nb > 0; nb -= c) { |
290 | c = max_align(ea); | |
291 | if (c > nb) | |
292 | c = max_align(nb); | |
e0a0986b PM |
293 | switch (c) { |
294 | case 1: | |
295 | err = __get_user(*dest, (unsigned char __user *) ea); | |
296 | break; | |
297 | case 2: | |
298 | err = __get_user(*(u16 *)dest, | |
299 | (unsigned short __user *) ea); | |
300 | break; | |
301 | case 4: | |
302 | err = __get_user(*(u32 *)dest, | |
303 | (unsigned int __user *) ea); | |
304 | break; | |
305 | #ifdef __powerpc64__ | |
306 | case 8: | |
307 | err = __get_user(*(unsigned long *)dest, | |
308 | (unsigned long __user *) ea); | |
309 | break; | |
310 | #endif | |
311 | } | |
b9da9c8a PM |
312 | if (err) { |
313 | regs->dar = ea; | |
0016a4cf | 314 | return err; |
b9da9c8a | 315 | } |
e0a0986b | 316 | dest += c; |
0016a4cf PM |
317 | ea += c; |
318 | } | |
0016a4cf PM |
319 | return 0; |
320 | } | |
321 | ||
e0a0986b PM |
322 | static nokprobe_inline int read_mem_unaligned(unsigned long *dest, |
323 | unsigned long ea, int nb, | |
324 | struct pt_regs *regs) | |
325 | { | |
326 | union { | |
327 | unsigned long ul; | |
328 | u8 b[sizeof(unsigned long)]; | |
329 | } u; | |
330 | int i; | |
331 | int err; | |
332 | ||
333 | u.ul = 0; | |
334 | i = IS_BE ? sizeof(unsigned long) - nb : 0; | |
b9da9c8a | 335 | err = copy_mem_in(&u.b[i], ea, nb, regs); |
e0a0986b PM |
336 | if (!err) |
337 | *dest = u.ul; | |
338 | return err; | |
339 | } | |
340 | ||
0016a4cf PM |
341 | /* |
342 | * Read memory at address ea for nb bytes, return 0 for success | |
e0a0986b PM |
343 | * or -EFAULT if an error occurred. N.B. nb must be 1, 2, 4 or 8. |
344 | * If nb < sizeof(long), the result is right-justified on BE systems. | |
0016a4cf | 345 | */ |
71f6e58e | 346 | static int read_mem(unsigned long *dest, unsigned long ea, int nb, |
0016a4cf PM |
347 | struct pt_regs *regs) |
348 | { | |
349 | if (!address_ok(regs, ea, nb)) | |
350 | return -EFAULT; | |
351 | if ((ea & (nb - 1)) == 0) | |
b9da9c8a | 352 | return read_mem_aligned(dest, ea, nb, regs); |
0016a4cf PM |
353 | return read_mem_unaligned(dest, ea, nb, regs); |
354 | } | |
71f6e58e | 355 | NOKPROBE_SYMBOL(read_mem); |
0016a4cf | 356 | |
71f6e58e | 357 | static nokprobe_inline int write_mem_aligned(unsigned long val, |
b9da9c8a PM |
358 | unsigned long ea, int nb, |
359 | struct pt_regs *regs) | |
0016a4cf PM |
360 | { |
361 | int err = 0; | |
362 | ||
363 | switch (nb) { | |
364 | case 1: | |
365 | err = __put_user(val, (unsigned char __user *) ea); | |
366 | break; | |
367 | case 2: | |
368 | err = __put_user(val, (unsigned short __user *) ea); | |
369 | break; | |
370 | case 4: | |
371 | err = __put_user(val, (unsigned int __user *) ea); | |
372 | break; | |
373 | #ifdef __powerpc64__ | |
374 | case 8: | |
375 | err = __put_user(val, (unsigned long __user *) ea); | |
376 | break; | |
377 | #endif | |
378 | } | |
b9da9c8a PM |
379 | if (err) |
380 | regs->dar = ea; | |
0016a4cf PM |
381 | return err; |
382 | } | |
383 | ||
e0a0986b PM |
384 | /* |
385 | * Copy from a buffer to userspace, using the largest possible | |
386 | * aligned accesses, up to sizeof(long). | |
387 | */ | |
174b701d | 388 | static nokprobe_inline int copy_mem_out(u8 *dest, unsigned long ea, int nb, |
b9da9c8a | 389 | struct pt_regs *regs) |
0016a4cf | 390 | { |
e0a0986b PM |
391 | int err = 0; |
392 | int c; | |
0016a4cf | 393 | |
0016a4cf PM |
394 | for (; nb > 0; nb -= c) { |
395 | c = max_align(ea); | |
396 | if (c > nb) | |
397 | c = max_align(nb); | |
e0a0986b PM |
398 | switch (c) { |
399 | case 1: | |
400 | err = __put_user(*dest, (unsigned char __user *) ea); | |
401 | break; | |
402 | case 2: | |
403 | err = __put_user(*(u16 *)dest, | |
404 | (unsigned short __user *) ea); | |
405 | break; | |
406 | case 4: | |
407 | err = __put_user(*(u32 *)dest, | |
408 | (unsigned int __user *) ea); | |
409 | break; | |
410 | #ifdef __powerpc64__ | |
411 | case 8: | |
412 | err = __put_user(*(unsigned long *)dest, | |
413 | (unsigned long __user *) ea); | |
414 | break; | |
415 | #endif | |
416 | } | |
b9da9c8a PM |
417 | if (err) { |
418 | regs->dar = ea; | |
0016a4cf | 419 | return err; |
b9da9c8a | 420 | } |
e0a0986b | 421 | dest += c; |
17e8de7e | 422 | ea += c; |
0016a4cf PM |
423 | } |
424 | return 0; | |
425 | } | |
426 | ||
e0a0986b PM |
427 | static nokprobe_inline int write_mem_unaligned(unsigned long val, |
428 | unsigned long ea, int nb, | |
429 | struct pt_regs *regs) | |
430 | { | |
431 | union { | |
432 | unsigned long ul; | |
433 | u8 b[sizeof(unsigned long)]; | |
434 | } u; | |
435 | int i; | |
436 | ||
437 | u.ul = val; | |
438 | i = IS_BE ? sizeof(unsigned long) - nb : 0; | |
b9da9c8a | 439 | return copy_mem_out(&u.b[i], ea, nb, regs); |
e0a0986b PM |
440 | } |
441 | ||
0016a4cf PM |
442 | /* |
443 | * Write memory at address ea for nb bytes, return 0 for success | |
e0a0986b | 444 | * or -EFAULT if an error occurred. N.B. nb must be 1, 2, 4 or 8. |
0016a4cf | 445 | */ |
71f6e58e | 446 | static int write_mem(unsigned long val, unsigned long ea, int nb, |
0016a4cf PM |
447 | struct pt_regs *regs) |
448 | { | |
449 | if (!address_ok(regs, ea, nb)) | |
450 | return -EFAULT; | |
451 | if ((ea & (nb - 1)) == 0) | |
b9da9c8a | 452 | return write_mem_aligned(val, ea, nb, regs); |
0016a4cf PM |
453 | return write_mem_unaligned(val, ea, nb, regs); |
454 | } | |
71f6e58e | 455 | NOKPROBE_SYMBOL(write_mem); |
0016a4cf | 456 | |
cd64d169 | 457 | #ifdef CONFIG_PPC_FPU |
14cf11af | 458 | /* |
c22435a5 PM |
459 | * These access either the real FP register or the image in the |
460 | * thread_struct, depending on regs->msr & MSR_FP. | |
0016a4cf | 461 | */ |
d2b65ac6 PM |
462 | static int do_fp_load(struct instruction_op *op, unsigned long ea, |
463 | struct pt_regs *regs, bool cross_endian) | |
0016a4cf | 464 | { |
d2b65ac6 | 465 | int err, rn, nb; |
c22435a5 | 466 | union { |
d2b65ac6 PM |
467 | int i; |
468 | unsigned int u; | |
c22435a5 | 469 | float f; |
1f41fb79 PM |
470 | double d[2]; |
471 | unsigned long l[2]; | |
472 | u8 b[2 * sizeof(double)]; | |
c22435a5 | 473 | } u; |
0016a4cf | 474 | |
d2b65ac6 | 475 | nb = GETSIZE(op->type); |
0016a4cf PM |
476 | if (!address_ok(regs, ea, nb)) |
477 | return -EFAULT; | |
d2b65ac6 | 478 | rn = op->reg; |
b9da9c8a | 479 | err = copy_mem_in(u.b, ea, nb, regs); |
c22435a5 PM |
480 | if (err) |
481 | return err; | |
d955189a PM |
482 | if (unlikely(cross_endian)) { |
483 | do_byte_reverse(u.b, min(nb, 8)); | |
484 | if (nb == 16) | |
485 | do_byte_reverse(&u.b[8], 8); | |
486 | } | |
c22435a5 | 487 | preempt_disable(); |
d2b65ac6 PM |
488 | if (nb == 4) { |
489 | if (op->type & FPCONV) | |
490 | conv_sp_to_dp(&u.f, &u.d[0]); | |
491 | else if (op->type & SIGNEXT) | |
492 | u.l[0] = u.i; | |
493 | else | |
494 | u.l[0] = u.u; | |
495 | } | |
c22435a5 | 496 | if (regs->msr & MSR_FP) |
1f41fb79 | 497 | put_fpr(rn, &u.d[0]); |
c22435a5 | 498 | else |
1f41fb79 PM |
499 | current->thread.TS_FPR(rn) = u.l[0]; |
500 | if (nb == 16) { | |
501 | /* lfdp */ | |
502 | rn |= 1; | |
503 | if (regs->msr & MSR_FP) | |
504 | put_fpr(rn, &u.d[1]); | |
505 | else | |
506 | current->thread.TS_FPR(rn) = u.l[1]; | |
507 | } | |
c22435a5 PM |
508 | preempt_enable(); |
509 | return 0; | |
0016a4cf | 510 | } |
71f6e58e | 511 | NOKPROBE_SYMBOL(do_fp_load); |
0016a4cf | 512 | |
d2b65ac6 PM |
513 | static int do_fp_store(struct instruction_op *op, unsigned long ea, |
514 | struct pt_regs *regs, bool cross_endian) | |
0016a4cf | 515 | { |
d2b65ac6 | 516 | int rn, nb; |
c22435a5 | 517 | union { |
d2b65ac6 | 518 | unsigned int u; |
c22435a5 | 519 | float f; |
1f41fb79 PM |
520 | double d[2]; |
521 | unsigned long l[2]; | |
522 | u8 b[2 * sizeof(double)]; | |
c22435a5 | 523 | } u; |
0016a4cf | 524 | |
d2b65ac6 | 525 | nb = GETSIZE(op->type); |
0016a4cf PM |
526 | if (!address_ok(regs, ea, nb)) |
527 | return -EFAULT; | |
d2b65ac6 | 528 | rn = op->reg; |
c22435a5 PM |
529 | preempt_disable(); |
530 | if (regs->msr & MSR_FP) | |
1f41fb79 | 531 | get_fpr(rn, &u.d[0]); |
c22435a5 | 532 | else |
1f41fb79 | 533 | u.l[0] = current->thread.TS_FPR(rn); |
d2b65ac6 PM |
534 | if (nb == 4) { |
535 | if (op->type & FPCONV) | |
536 | conv_dp_to_sp(&u.d[0], &u.f); | |
537 | else | |
538 | u.u = u.l[0]; | |
539 | } | |
1f41fb79 PM |
540 | if (nb == 16) { |
541 | rn |= 1; | |
542 | if (regs->msr & MSR_FP) | |
543 | get_fpr(rn, &u.d[1]); | |
544 | else | |
545 | u.l[1] = current->thread.TS_FPR(rn); | |
546 | } | |
c22435a5 | 547 | preempt_enable(); |
d955189a PM |
548 | if (unlikely(cross_endian)) { |
549 | do_byte_reverse(u.b, min(nb, 8)); | |
550 | if (nb == 16) | |
551 | do_byte_reverse(&u.b[8], 8); | |
552 | } | |
b9da9c8a | 553 | return copy_mem_out(u.b, ea, nb, regs); |
0016a4cf | 554 | } |
71f6e58e | 555 | NOKPROBE_SYMBOL(do_fp_store); |
cd64d169 | 556 | #endif |
0016a4cf PM |
557 | |
558 | #ifdef CONFIG_ALTIVEC | |
559 | /* For Altivec/VMX, no need to worry about alignment */ | |
c22435a5 | 560 | static nokprobe_inline int do_vec_load(int rn, unsigned long ea, |
d955189a PM |
561 | int size, struct pt_regs *regs, |
562 | bool cross_endian) | |
0016a4cf | 563 | { |
c22435a5 PM |
564 | int err; |
565 | union { | |
566 | __vector128 v; | |
567 | u8 b[sizeof(__vector128)]; | |
568 | } u = {}; | |
569 | ||
0016a4cf PM |
570 | if (!address_ok(regs, ea & ~0xfUL, 16)) |
571 | return -EFAULT; | |
c22435a5 PM |
572 | /* align to multiple of size */ |
573 | ea &= ~(size - 1); | |
b9da9c8a | 574 | err = copy_mem_in(&u.b[ea & 0xf], ea, size, regs); |
c22435a5 PM |
575 | if (err) |
576 | return err; | |
d955189a PM |
577 | if (unlikely(cross_endian)) |
578 | do_byte_reverse(&u.b[ea & 0xf], size); | |
c22435a5 PM |
579 | preempt_disable(); |
580 | if (regs->msr & MSR_VEC) | |
581 | put_vr(rn, &u.v); | |
582 | else | |
583 | current->thread.vr_state.vr[rn] = u.v; | |
584 | preempt_enable(); | |
585 | return 0; | |
0016a4cf PM |
586 | } |
587 | ||
c22435a5 | 588 | static nokprobe_inline int do_vec_store(int rn, unsigned long ea, |
d955189a PM |
589 | int size, struct pt_regs *regs, |
590 | bool cross_endian) | |
0016a4cf | 591 | { |
c22435a5 PM |
592 | union { |
593 | __vector128 v; | |
594 | u8 b[sizeof(__vector128)]; | |
595 | } u; | |
596 | ||
0016a4cf PM |
597 | if (!address_ok(regs, ea & ~0xfUL, 16)) |
598 | return -EFAULT; | |
c22435a5 PM |
599 | /* align to multiple of size */ |
600 | ea &= ~(size - 1); | |
601 | ||
602 | preempt_disable(); | |
603 | if (regs->msr & MSR_VEC) | |
604 | get_vr(rn, &u.v); | |
605 | else | |
606 | u.v = current->thread.vr_state.vr[rn]; | |
607 | preempt_enable(); | |
d955189a PM |
608 | if (unlikely(cross_endian)) |
609 | do_byte_reverse(&u.b[ea & 0xf], size); | |
b9da9c8a | 610 | return copy_mem_out(&u.b[ea & 0xf], ea, size, regs); |
0016a4cf PM |
611 | } |
612 | #endif /* CONFIG_ALTIVEC */ | |
613 | ||
350779a2 PM |
614 | #ifdef __powerpc64__ |
615 | static nokprobe_inline int emulate_lq(struct pt_regs *regs, unsigned long ea, | |
d955189a | 616 | int reg, bool cross_endian) |
0016a4cf PM |
617 | { |
618 | int err; | |
0016a4cf PM |
619 | |
620 | if (!address_ok(regs, ea, 16)) | |
621 | return -EFAULT; | |
350779a2 | 622 | /* if aligned, should be atomic */ |
d955189a PM |
623 | if ((ea & 0xf) == 0) { |
624 | err = do_lq(ea, ®s->gpr[reg]); | |
625 | } else { | |
626 | err = read_mem(®s->gpr[reg + IS_LE], ea, 8, regs); | |
627 | if (!err) | |
628 | err = read_mem(®s->gpr[reg + IS_BE], ea + 8, 8, regs); | |
629 | } | |
630 | if (!err && unlikely(cross_endian)) | |
631 | do_byte_reverse(®s->gpr[reg], 16); | |
0016a4cf PM |
632 | return err; |
633 | } | |
634 | ||
350779a2 | 635 | static nokprobe_inline int emulate_stq(struct pt_regs *regs, unsigned long ea, |
d955189a | 636 | int reg, bool cross_endian) |
0016a4cf PM |
637 | { |
638 | int err; | |
d955189a | 639 | unsigned long vals[2]; |
0016a4cf PM |
640 | |
641 | if (!address_ok(regs, ea, 16)) | |
642 | return -EFAULT; | |
d955189a PM |
643 | vals[0] = regs->gpr[reg]; |
644 | vals[1] = regs->gpr[reg + 1]; | |
645 | if (unlikely(cross_endian)) | |
646 | do_byte_reverse(vals, 16); | |
647 | ||
350779a2 PM |
648 | /* if aligned, should be atomic */ |
649 | if ((ea & 0xf) == 0) | |
d955189a | 650 | return do_stq(ea, vals[0], vals[1]); |
350779a2 | 651 | |
d955189a | 652 | err = write_mem(vals[IS_LE], ea, 8, regs); |
0016a4cf | 653 | if (!err) |
d955189a | 654 | err = write_mem(vals[IS_BE], ea + 8, 8, regs); |
0016a4cf PM |
655 | return err; |
656 | } | |
350779a2 PM |
657 | #endif /* __powerpc64 */ |
658 | ||
659 | #ifdef CONFIG_VSX | |
660 | void emulate_vsx_load(struct instruction_op *op, union vsx_reg *reg, | |
d955189a | 661 | const void *mem, bool rev) |
350779a2 PM |
662 | { |
663 | int size, read_size; | |
664 | int i, j; | |
665 | const unsigned int *wp; | |
666 | const unsigned short *hp; | |
667 | const unsigned char *bp; | |
668 | ||
669 | size = GETSIZE(op->type); | |
670 | reg->d[0] = reg->d[1] = 0; | |
671 | ||
672 | switch (op->element_size) { | |
673 | case 16: | |
674 | /* whole vector; lxv[x] or lxvl[l] */ | |
675 | if (size == 0) | |
676 | break; | |
677 | memcpy(reg, mem, size); | |
d955189a PM |
678 | if (IS_LE && (op->vsx_flags & VSX_LDLEFT)) |
679 | rev = !rev; | |
680 | if (rev) | |
681 | do_byte_reverse(reg, 16); | |
350779a2 PM |
682 | break; |
683 | case 8: | |
684 | /* scalar loads, lxvd2x, lxvdsx */ | |
685 | read_size = (size >= 8) ? 8 : size; | |
686 | i = IS_LE ? 8 : 8 - read_size; | |
687 | memcpy(®->b[i], mem, read_size); | |
d955189a PM |
688 | if (rev) |
689 | do_byte_reverse(®->b[i], 8); | |
350779a2 PM |
690 | if (size < 8) { |
691 | if (op->type & SIGNEXT) { | |
692 | /* size == 4 is the only case here */ | |
693 | reg->d[IS_LE] = (signed int) reg->d[IS_LE]; | |
694 | } else if (op->vsx_flags & VSX_FPCONV) { | |
695 | preempt_disable(); | |
696 | conv_sp_to_dp(®->fp[1 + IS_LE], | |
697 | ®->dp[IS_LE]); | |
698 | preempt_enable(); | |
699 | } | |
700 | } else { | |
d955189a PM |
701 | if (size == 16) { |
702 | unsigned long v = *(unsigned long *)(mem + 8); | |
703 | reg->d[IS_BE] = !rev ? v : byterev_8(v); | |
704 | } else if (op->vsx_flags & VSX_SPLAT) | |
350779a2 PM |
705 | reg->d[IS_BE] = reg->d[IS_LE]; |
706 | } | |
707 | break; | |
708 | case 4: | |
709 | /* lxvw4x, lxvwsx */ | |
710 | wp = mem; | |
711 | for (j = 0; j < size / 4; ++j) { | |
712 | i = IS_LE ? 3 - j : j; | |
d955189a | 713 | reg->w[i] = !rev ? *wp++ : byterev_4(*wp++); |
350779a2 PM |
714 | } |
715 | if (op->vsx_flags & VSX_SPLAT) { | |
716 | u32 val = reg->w[IS_LE ? 3 : 0]; | |
717 | for (; j < 4; ++j) { | |
718 | i = IS_LE ? 3 - j : j; | |
719 | reg->w[i] = val; | |
720 | } | |
721 | } | |
722 | break; | |
723 | case 2: | |
724 | /* lxvh8x */ | |
725 | hp = mem; | |
726 | for (j = 0; j < size / 2; ++j) { | |
727 | i = IS_LE ? 7 - j : j; | |
d955189a | 728 | reg->h[i] = !rev ? *hp++ : byterev_2(*hp++); |
350779a2 PM |
729 | } |
730 | break; | |
731 | case 1: | |
732 | /* lxvb16x */ | |
733 | bp = mem; | |
734 | for (j = 0; j < size; ++j) { | |
735 | i = IS_LE ? 15 - j : j; | |
736 | reg->b[i] = *bp++; | |
737 | } | |
738 | break; | |
739 | } | |
740 | } | |
741 | EXPORT_SYMBOL_GPL(emulate_vsx_load); | |
742 | NOKPROBE_SYMBOL(emulate_vsx_load); | |
743 | ||
744 | void emulate_vsx_store(struct instruction_op *op, const union vsx_reg *reg, | |
d955189a | 745 | void *mem, bool rev) |
350779a2 PM |
746 | { |
747 | int size, write_size; | |
748 | int i, j; | |
749 | union vsx_reg buf; | |
750 | unsigned int *wp; | |
751 | unsigned short *hp; | |
752 | unsigned char *bp; | |
753 | ||
754 | size = GETSIZE(op->type); | |
755 | ||
756 | switch (op->element_size) { | |
757 | case 16: | |
758 | /* stxv, stxvx, stxvl, stxvll */ | |
759 | if (size == 0) | |
760 | break; | |
d955189a PM |
761 | if (IS_LE && (op->vsx_flags & VSX_LDLEFT)) |
762 | rev = !rev; | |
763 | if (rev) { | |
350779a2 PM |
764 | /* reverse 16 bytes */ |
765 | buf.d[0] = byterev_8(reg->d[1]); | |
766 | buf.d[1] = byterev_8(reg->d[0]); | |
767 | reg = &buf; | |
768 | } | |
769 | memcpy(mem, reg, size); | |
770 | break; | |
771 | case 8: | |
772 | /* scalar stores, stxvd2x */ | |
773 | write_size = (size >= 8) ? 8 : size; | |
774 | i = IS_LE ? 8 : 8 - write_size; | |
775 | if (size < 8 && op->vsx_flags & VSX_FPCONV) { | |
776 | buf.d[0] = buf.d[1] = 0; | |
777 | preempt_disable(); | |
778 | conv_dp_to_sp(®->dp[IS_LE], &buf.fp[1 + IS_LE]); | |
779 | preempt_enable(); | |
780 | reg = &buf; | |
781 | } | |
782 | memcpy(mem, ®->b[i], write_size); | |
783 | if (size == 16) | |
784 | memcpy(mem + 8, ®->d[IS_BE], 8); | |
d955189a PM |
785 | if (unlikely(rev)) { |
786 | do_byte_reverse(mem, write_size); | |
787 | if (size == 16) | |
788 | do_byte_reverse(mem + 8, 8); | |
789 | } | |
350779a2 PM |
790 | break; |
791 | case 4: | |
792 | /* stxvw4x */ | |
793 | wp = mem; | |
794 | for (j = 0; j < size / 4; ++j) { | |
795 | i = IS_LE ? 3 - j : j; | |
d955189a | 796 | *wp++ = !rev ? reg->w[i] : byterev_4(reg->w[i]); |
350779a2 PM |
797 | } |
798 | break; | |
799 | case 2: | |
800 | /* stxvh8x */ | |
801 | hp = mem; | |
802 | for (j = 0; j < size / 2; ++j) { | |
803 | i = IS_LE ? 7 - j : j; | |
d955189a | 804 | *hp++ = !rev ? reg->h[i] : byterev_2(reg->h[i]); |
350779a2 PM |
805 | } |
806 | break; | |
807 | case 1: | |
808 | /* stvxb16x */ | |
809 | bp = mem; | |
810 | for (j = 0; j < size; ++j) { | |
811 | i = IS_LE ? 15 - j : j; | |
812 | *bp++ = reg->b[i]; | |
813 | } | |
814 | break; | |
815 | } | |
816 | } | |
817 | EXPORT_SYMBOL_GPL(emulate_vsx_store); | |
818 | NOKPROBE_SYMBOL(emulate_vsx_store); | |
c22435a5 PM |
819 | |
820 | static nokprobe_inline int do_vsx_load(struct instruction_op *op, | |
d955189a PM |
821 | unsigned long ea, struct pt_regs *regs, |
822 | bool cross_endian) | |
c22435a5 PM |
823 | { |
824 | int reg = op->reg; | |
825 | u8 mem[16]; | |
826 | union vsx_reg buf; | |
827 | int size = GETSIZE(op->type); | |
828 | ||
b9da9c8a | 829 | if (!address_ok(regs, ea, size) || copy_mem_in(mem, ea, size, regs)) |
c22435a5 PM |
830 | return -EFAULT; |
831 | ||
d955189a | 832 | emulate_vsx_load(op, &buf, mem, cross_endian); |
c22435a5 PM |
833 | preempt_disable(); |
834 | if (reg < 32) { | |
835 | /* FP regs + extensions */ | |
836 | if (regs->msr & MSR_FP) { | |
837 | load_vsrn(reg, &buf); | |
838 | } else { | |
839 | current->thread.fp_state.fpr[reg][0] = buf.d[0]; | |
840 | current->thread.fp_state.fpr[reg][1] = buf.d[1]; | |
841 | } | |
842 | } else { | |
843 | if (regs->msr & MSR_VEC) | |
844 | load_vsrn(reg, &buf); | |
845 | else | |
846 | current->thread.vr_state.vr[reg - 32] = buf.v; | |
847 | } | |
848 | preempt_enable(); | |
849 | return 0; | |
850 | } | |
851 | ||
852 | static nokprobe_inline int do_vsx_store(struct instruction_op *op, | |
d955189a PM |
853 | unsigned long ea, struct pt_regs *regs, |
854 | bool cross_endian) | |
c22435a5 PM |
855 | { |
856 | int reg = op->reg; | |
857 | u8 mem[16]; | |
858 | union vsx_reg buf; | |
859 | int size = GETSIZE(op->type); | |
860 | ||
861 | if (!address_ok(regs, ea, size)) | |
862 | return -EFAULT; | |
863 | ||
864 | preempt_disable(); | |
865 | if (reg < 32) { | |
866 | /* FP regs + extensions */ | |
867 | if (regs->msr & MSR_FP) { | |
868 | store_vsrn(reg, &buf); | |
869 | } else { | |
870 | buf.d[0] = current->thread.fp_state.fpr[reg][0]; | |
871 | buf.d[1] = current->thread.fp_state.fpr[reg][1]; | |
872 | } | |
873 | } else { | |
874 | if (regs->msr & MSR_VEC) | |
875 | store_vsrn(reg, &buf); | |
876 | else | |
877 | buf.v = current->thread.vr_state.vr[reg - 32]; | |
878 | } | |
879 | preempt_enable(); | |
d955189a | 880 | emulate_vsx_store(op, &buf, mem, cross_endian); |
b9da9c8a | 881 | return copy_mem_out(mem, ea, size, regs); |
c22435a5 | 882 | } |
0016a4cf PM |
883 | #endif /* CONFIG_VSX */ |
884 | ||
b2543f7b PM |
885 | int emulate_dcbz(unsigned long ea, struct pt_regs *regs) |
886 | { | |
887 | int err; | |
888 | unsigned long i, size; | |
889 | ||
890 | #ifdef __powerpc64__ | |
891 | size = ppc64_caches.l1d.block_size; | |
892 | if (!(regs->msr & MSR_64BIT)) | |
893 | ea &= 0xffffffffUL; | |
894 | #else | |
895 | size = L1_CACHE_BYTES; | |
896 | #endif | |
897 | ea &= ~(size - 1); | |
898 | if (!address_ok(regs, ea, size)) | |
899 | return -EFAULT; | |
900 | for (i = 0; i < size; i += sizeof(long)) { | |
901 | err = __put_user(0, (unsigned long __user *) (ea + i)); | |
b9da9c8a PM |
902 | if (err) { |
903 | regs->dar = ea; | |
b2543f7b | 904 | return err; |
b9da9c8a | 905 | } |
b2543f7b PM |
906 | } |
907 | return 0; | |
908 | } | |
909 | NOKPROBE_SYMBOL(emulate_dcbz); | |
910 | ||
0016a4cf PM |
911 | #define __put_user_asmx(x, addr, err, op, cr) \ |
912 | __asm__ __volatile__( \ | |
913 | "1: " op " %2,0,%3\n" \ | |
914 | " mfcr %1\n" \ | |
915 | "2:\n" \ | |
916 | ".section .fixup,\"ax\"\n" \ | |
917 | "3: li %0,%4\n" \ | |
918 | " b 2b\n" \ | |
919 | ".previous\n" \ | |
24bfa6a9 | 920 | EX_TABLE(1b, 3b) \ |
0016a4cf PM |
921 | : "=r" (err), "=r" (cr) \ |
922 | : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err)) | |
923 | ||
924 | #define __get_user_asmx(x, addr, err, op) \ | |
925 | __asm__ __volatile__( \ | |
926 | "1: "op" %1,0,%2\n" \ | |
927 | "2:\n" \ | |
928 | ".section .fixup,\"ax\"\n" \ | |
929 | "3: li %0,%3\n" \ | |
930 | " b 2b\n" \ | |
931 | ".previous\n" \ | |
24bfa6a9 | 932 | EX_TABLE(1b, 3b) \ |
0016a4cf PM |
933 | : "=r" (err), "=r" (x) \ |
934 | : "r" (addr), "i" (-EFAULT), "0" (err)) | |
935 | ||
936 | #define __cacheop_user_asmx(addr, err, op) \ | |
937 | __asm__ __volatile__( \ | |
938 | "1: "op" 0,%1\n" \ | |
939 | "2:\n" \ | |
940 | ".section .fixup,\"ax\"\n" \ | |
941 | "3: li %0,%3\n" \ | |
942 | " b 2b\n" \ | |
943 | ".previous\n" \ | |
24bfa6a9 | 944 | EX_TABLE(1b, 3b) \ |
0016a4cf PM |
945 | : "=r" (err) \ |
946 | : "r" (addr), "i" (-EFAULT), "0" (err)) | |
947 | ||
3cdfcbfd | 948 | static nokprobe_inline void set_cr0(const struct pt_regs *regs, |
ad47ff3e | 949 | struct instruction_op *op) |
0016a4cf | 950 | { |
ad47ff3e | 951 | long val = op->val; |
0016a4cf | 952 | |
3cdfcbfd PM |
953 | op->type |= SETCC; |
954 | op->ccval = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000); | |
0016a4cf | 955 | #ifdef __powerpc64__ |
b91e136c | 956 | if (!(regs->msr & MSR_64BIT)) |
0016a4cf PM |
957 | val = (int) val; |
958 | #endif | |
959 | if (val < 0) | |
3cdfcbfd | 960 | op->ccval |= 0x80000000; |
0016a4cf | 961 | else if (val > 0) |
3cdfcbfd | 962 | op->ccval |= 0x40000000; |
0016a4cf | 963 | else |
3cdfcbfd | 964 | op->ccval |= 0x20000000; |
0016a4cf PM |
965 | } |
966 | ||
dc39c1d6 SD |
967 | static nokprobe_inline void set_ca32(struct instruction_op *op, bool val) |
968 | { | |
969 | if (cpu_has_feature(CPU_FTR_ARCH_300)) { | |
970 | if (val) | |
971 | op->xerval |= XER_CA32; | |
972 | else | |
973 | op->xerval &= ~XER_CA32; | |
974 | } | |
975 | } | |
976 | ||
3cdfcbfd PM |
977 | static nokprobe_inline void add_with_carry(const struct pt_regs *regs, |
978 | struct instruction_op *op, int rd, | |
0016a4cf PM |
979 | unsigned long val1, unsigned long val2, |
980 | unsigned long carry_in) | |
981 | { | |
982 | unsigned long val = val1 + val2; | |
983 | ||
984 | if (carry_in) | |
985 | ++val; | |
3cdfcbfd PM |
986 | op->type = COMPUTE + SETREG + SETXER; |
987 | op->reg = rd; | |
988 | op->val = val; | |
0016a4cf | 989 | #ifdef __powerpc64__ |
b91e136c | 990 | if (!(regs->msr & MSR_64BIT)) { |
0016a4cf PM |
991 | val = (unsigned int) val; |
992 | val1 = (unsigned int) val1; | |
993 | } | |
994 | #endif | |
3cdfcbfd | 995 | op->xerval = regs->xer; |
0016a4cf | 996 | if (val < val1 || (carry_in && val == val1)) |
3cdfcbfd | 997 | op->xerval |= XER_CA; |
0016a4cf | 998 | else |
3cdfcbfd | 999 | op->xerval &= ~XER_CA; |
dc39c1d6 SD |
1000 | |
1001 | set_ca32(op, (unsigned int)val < (unsigned int)val1 || | |
1002 | (carry_in && (unsigned int)val == (unsigned int)val1)); | |
0016a4cf PM |
1003 | } |
1004 | ||
3cdfcbfd PM |
1005 | static nokprobe_inline void do_cmp_signed(const struct pt_regs *regs, |
1006 | struct instruction_op *op, | |
1007 | long v1, long v2, int crfld) | |
0016a4cf PM |
1008 | { |
1009 | unsigned int crval, shift; | |
1010 | ||
3cdfcbfd | 1011 | op->type = COMPUTE + SETCC; |
0016a4cf PM |
1012 | crval = (regs->xer >> 31) & 1; /* get SO bit */ |
1013 | if (v1 < v2) | |
1014 | crval |= 8; | |
1015 | else if (v1 > v2) | |
1016 | crval |= 4; | |
1017 | else | |
1018 | crval |= 2; | |
1019 | shift = (7 - crfld) * 4; | |
3cdfcbfd | 1020 | op->ccval = (regs->ccr & ~(0xf << shift)) | (crval << shift); |
0016a4cf PM |
1021 | } |
1022 | ||
3cdfcbfd PM |
1023 | static nokprobe_inline void do_cmp_unsigned(const struct pt_regs *regs, |
1024 | struct instruction_op *op, | |
1025 | unsigned long v1, | |
1026 | unsigned long v2, int crfld) | |
0016a4cf PM |
1027 | { |
1028 | unsigned int crval, shift; | |
1029 | ||
3cdfcbfd | 1030 | op->type = COMPUTE + SETCC; |
0016a4cf PM |
1031 | crval = (regs->xer >> 31) & 1; /* get SO bit */ |
1032 | if (v1 < v2) | |
1033 | crval |= 8; | |
1034 | else if (v1 > v2) | |
1035 | crval |= 4; | |
1036 | else | |
1037 | crval |= 2; | |
1038 | shift = (7 - crfld) * 4; | |
3cdfcbfd | 1039 | op->ccval = (regs->ccr & ~(0xf << shift)) | (crval << shift); |
0016a4cf PM |
1040 | } |
1041 | ||
3cdfcbfd PM |
1042 | static nokprobe_inline void do_cmpb(const struct pt_regs *regs, |
1043 | struct instruction_op *op, | |
1044 | unsigned long v1, unsigned long v2) | |
02c0f62a MB |
1045 | { |
1046 | unsigned long long out_val, mask; | |
1047 | int i; | |
1048 | ||
1049 | out_val = 0; | |
1050 | for (i = 0; i < 8; i++) { | |
1051 | mask = 0xffUL << (i * 8); | |
1052 | if ((v1 & mask) == (v2 & mask)) | |
1053 | out_val |= mask; | |
1054 | } | |
3cdfcbfd | 1055 | op->val = out_val; |
02c0f62a MB |
1056 | } |
1057 | ||
dcbd19b4 MB |
1058 | /* |
1059 | * The size parameter is used to adjust the equivalent popcnt instruction. | |
1060 | * popcntb = 8, popcntw = 32, popcntd = 64 | |
1061 | */ | |
3cdfcbfd PM |
1062 | static nokprobe_inline void do_popcnt(const struct pt_regs *regs, |
1063 | struct instruction_op *op, | |
1064 | unsigned long v1, int size) | |
dcbd19b4 MB |
1065 | { |
1066 | unsigned long long out = v1; | |
1067 | ||
20acf7fc FT |
1068 | out -= (out >> 1) & 0x5555555555555555ULL; |
1069 | out = (0x3333333333333333ULL & out) + | |
1070 | (0x3333333333333333ULL & (out >> 2)); | |
1071 | out = (out + (out >> 4)) & 0x0f0f0f0f0f0f0f0fULL; | |
dcbd19b4 MB |
1072 | |
1073 | if (size == 8) { /* popcntb */ | |
3cdfcbfd | 1074 | op->val = out; |
dcbd19b4 MB |
1075 | return; |
1076 | } | |
1077 | out += out >> 8; | |
1078 | out += out >> 16; | |
1079 | if (size == 32) { /* popcntw */ | |
20acf7fc | 1080 | op->val = out & 0x0000003f0000003fULL; |
dcbd19b4 MB |
1081 | return; |
1082 | } | |
1083 | ||
1084 | out = (out + (out >> 32)) & 0x7f; | |
3cdfcbfd | 1085 | op->val = out; /* popcntd */ |
dcbd19b4 MB |
1086 | } |
1087 | ||
f312793d | 1088 | #ifdef CONFIG_PPC64 |
3cdfcbfd PM |
1089 | static nokprobe_inline void do_bpermd(const struct pt_regs *regs, |
1090 | struct instruction_op *op, | |
1091 | unsigned long v1, unsigned long v2) | |
f312793d MB |
1092 | { |
1093 | unsigned char perm, idx; | |
1094 | unsigned int i; | |
1095 | ||
1096 | perm = 0; | |
1097 | for (i = 0; i < 8; i++) { | |
1098 | idx = (v1 >> (i * 8)) & 0xff; | |
1099 | if (idx < 64) | |
1100 | if (v2 & PPC_BIT(idx)) | |
1101 | perm |= 1 << i; | |
1102 | } | |
3cdfcbfd | 1103 | op->val = perm; |
f312793d MB |
1104 | } |
1105 | #endif /* CONFIG_PPC64 */ | |
2c979c48 MB |
1106 | /* |
1107 | * The size parameter adjusts the equivalent prty instruction. | |
1108 | * prtyw = 32, prtyd = 64 | |
1109 | */ | |
3cdfcbfd PM |
1110 | static nokprobe_inline void do_prty(const struct pt_regs *regs, |
1111 | struct instruction_op *op, | |
1112 | unsigned long v, int size) | |
2c979c48 MB |
1113 | { |
1114 | unsigned long long res = v ^ (v >> 8); | |
1115 | ||
1116 | res ^= res >> 16; | |
1117 | if (size == 32) { /* prtyw */ | |
20acf7fc | 1118 | op->val = res & 0x0000000100000001ULL; |
2c979c48 MB |
1119 | return; |
1120 | } | |
1121 | ||
1122 | res ^= res >> 32; | |
3cdfcbfd | 1123 | op->val = res & 1; /*prtyd */ |
2c979c48 | 1124 | } |
f312793d | 1125 | |
71f6e58e | 1126 | static nokprobe_inline int trap_compare(long v1, long v2) |
cf87c3f6 PM |
1127 | { |
1128 | int ret = 0; | |
1129 | ||
1130 | if (v1 < v2) | |
1131 | ret |= 0x10; | |
1132 | else if (v1 > v2) | |
1133 | ret |= 0x08; | |
1134 | else | |
1135 | ret |= 0x04; | |
1136 | if ((unsigned long)v1 < (unsigned long)v2) | |
1137 | ret |= 0x02; | |
1138 | else if ((unsigned long)v1 > (unsigned long)v2) | |
1139 | ret |= 0x01; | |
1140 | return ret; | |
1141 | } | |
1142 | ||
0016a4cf PM |
1143 | /* |
1144 | * Elements of 32-bit rotate and mask instructions. | |
1145 | */ | |
1146 | #define MASK32(mb, me) ((0xffffffffUL >> (mb)) + \ | |
1147 | ((signed long)-0x80000000L >> (me)) + ((me) >= (mb))) | |
1148 | #ifdef __powerpc64__ | |
1149 | #define MASK64_L(mb) (~0UL >> (mb)) | |
1150 | #define MASK64_R(me) ((signed long)-0x8000000000000000L >> (me)) | |
1151 | #define MASK64(mb, me) (MASK64_L(mb) + MASK64_R(me) + ((me) >= (mb))) | |
1152 | #define DATA32(x) (((x) & 0xffffffffUL) | (((x) & 0xffffffffUL) << 32)) | |
1153 | #else | |
1154 | #define DATA32(x) (x) | |
1155 | #endif | |
1156 | #define ROTATE(x, n) ((n) ? (((x) << (n)) | ((x) >> (8 * sizeof(long) - (n)))) : (x)) | |
1157 | ||
1158 | /* | |
3cdfcbfd PM |
1159 | * Decode an instruction, and return information about it in *op |
1160 | * without changing *regs. | |
1161 | * Integer arithmetic and logical instructions, branches, and barrier | |
1162 | * instructions can be emulated just using the information in *op. | |
1163 | * | |
1164 | * Return value is 1 if the instruction can be emulated just by | |
1165 | * updating *regs with the information in *op, -1 if we need the | |
1166 | * GPRs but *regs doesn't contain the full register set, or 0 | |
1167 | * otherwise. | |
14cf11af | 1168 | */ |
3cdfcbfd PM |
1169 | int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, |
1170 | unsigned int instr) | |
14cf11af | 1171 | { |
930d6288 | 1172 | unsigned int opcode, ra, rb, rc, rd, spr, u; |
14cf11af | 1173 | unsigned long int imm; |
0016a4cf | 1174 | unsigned long int val, val2; |
be96f633 | 1175 | unsigned int mb, me, sh; |
0016a4cf | 1176 | long ival; |
14cf11af | 1177 | |
be96f633 PM |
1178 | op->type = COMPUTE; |
1179 | ||
14cf11af PM |
1180 | opcode = instr >> 26; |
1181 | switch (opcode) { | |
1182 | case 16: /* bc */ | |
be96f633 | 1183 | op->type = BRANCH; |
14cf11af PM |
1184 | imm = (signed short)(instr & 0xfffc); |
1185 | if ((instr & 2) == 0) | |
1186 | imm += regs->nip; | |
3cdfcbfd | 1187 | op->val = truncate_if_32bit(regs->msr, imm); |
14cf11af | 1188 | if (instr & 1) |
3cdfcbfd PM |
1189 | op->type |= SETLK; |
1190 | if (branch_taken(instr, regs, op)) | |
1191 | op->type |= BRTAKEN; | |
14cf11af | 1192 | return 1; |
c032524f | 1193 | #ifdef CONFIG_PPC64 |
14cf11af | 1194 | case 17: /* sc */ |
be96f633 PM |
1195 | if ((instr & 0xfe2) == 2) |
1196 | op->type = SYSCALL; | |
1197 | else | |
1198 | op->type = UNKNOWN; | |
1199 | return 0; | |
c032524f | 1200 | #endif |
14cf11af | 1201 | case 18: /* b */ |
3cdfcbfd | 1202 | op->type = BRANCH | BRTAKEN; |
14cf11af PM |
1203 | imm = instr & 0x03fffffc; |
1204 | if (imm & 0x02000000) | |
1205 | imm -= 0x04000000; | |
1206 | if ((instr & 2) == 0) | |
1207 | imm += regs->nip; | |
3cdfcbfd | 1208 | op->val = truncate_if_32bit(regs->msr, imm); |
b91e136c | 1209 | if (instr & 1) |
3cdfcbfd | 1210 | op->type |= SETLK; |
14cf11af PM |
1211 | return 1; |
1212 | case 19: | |
0016a4cf | 1213 | switch ((instr >> 1) & 0x3ff) { |
cf87c3f6 | 1214 | case 0: /* mcrf */ |
3cdfcbfd | 1215 | op->type = COMPUTE + SETCC; |
87c4b83e AB |
1216 | rd = 7 - ((instr >> 23) & 0x7); |
1217 | ra = 7 - ((instr >> 18) & 0x7); | |
1218 | rd *= 4; | |
1219 | ra *= 4; | |
cf87c3f6 | 1220 | val = (regs->ccr >> ra) & 0xf; |
3cdfcbfd PM |
1221 | op->ccval = (regs->ccr & ~(0xfUL << rd)) | (val << rd); |
1222 | return 1; | |
cf87c3f6 | 1223 | |
0016a4cf PM |
1224 | case 16: /* bclr */ |
1225 | case 528: /* bcctr */ | |
be96f633 | 1226 | op->type = BRANCH; |
14cf11af | 1227 | imm = (instr & 0x400)? regs->ctr: regs->link; |
3cdfcbfd | 1228 | op->val = truncate_if_32bit(regs->msr, imm); |
14cf11af | 1229 | if (instr & 1) |
3cdfcbfd PM |
1230 | op->type |= SETLK; |
1231 | if (branch_taken(instr, regs, op)) | |
1232 | op->type |= BRTAKEN; | |
14cf11af | 1233 | return 1; |
0016a4cf PM |
1234 | |
1235 | case 18: /* rfid, scary */ | |
be96f633 PM |
1236 | if (regs->msr & MSR_PR) |
1237 | goto priv; | |
1238 | op->type = RFI; | |
1239 | return 0; | |
0016a4cf PM |
1240 | |
1241 | case 150: /* isync */ | |
3cdfcbfd PM |
1242 | op->type = BARRIER | BARRIER_ISYNC; |
1243 | return 1; | |
0016a4cf PM |
1244 | |
1245 | case 33: /* crnor */ | |
1246 | case 129: /* crandc */ | |
1247 | case 193: /* crxor */ | |
1248 | case 225: /* crnand */ | |
1249 | case 257: /* crand */ | |
1250 | case 289: /* creqv */ | |
1251 | case 417: /* crorc */ | |
1252 | case 449: /* cror */ | |
3cdfcbfd | 1253 | op->type = COMPUTE + SETCC; |
0016a4cf PM |
1254 | ra = (instr >> 16) & 0x1f; |
1255 | rb = (instr >> 11) & 0x1f; | |
1256 | rd = (instr >> 21) & 0x1f; | |
1257 | ra = (regs->ccr >> (31 - ra)) & 1; | |
1258 | rb = (regs->ccr >> (31 - rb)) & 1; | |
1259 | val = (instr >> (6 + ra * 2 + rb)) & 1; | |
3cdfcbfd | 1260 | op->ccval = (regs->ccr & ~(1UL << (31 - rd))) | |
0016a4cf | 1261 | (val << (31 - rd)); |
3cdfcbfd | 1262 | return 1; |
0016a4cf PM |
1263 | } |
1264 | break; | |
1265 | case 31: | |
1266 | switch ((instr >> 1) & 0x3ff) { | |
1267 | case 598: /* sync */ | |
3cdfcbfd | 1268 | op->type = BARRIER + BARRIER_SYNC; |
0016a4cf PM |
1269 | #ifdef __powerpc64__ |
1270 | switch ((instr >> 21) & 3) { | |
1271 | case 1: /* lwsync */ | |
3cdfcbfd PM |
1272 | op->type = BARRIER + BARRIER_LWSYNC; |
1273 | break; | |
0016a4cf | 1274 | case 2: /* ptesync */ |
3cdfcbfd PM |
1275 | op->type = BARRIER + BARRIER_PTESYNC; |
1276 | break; | |
0016a4cf PM |
1277 | } |
1278 | #endif | |
3cdfcbfd | 1279 | return 1; |
0016a4cf PM |
1280 | |
1281 | case 854: /* eieio */ | |
3cdfcbfd PM |
1282 | op->type = BARRIER + BARRIER_EIEIO; |
1283 | return 1; | |
0016a4cf PM |
1284 | } |
1285 | break; | |
1286 | } | |
1287 | ||
1288 | /* Following cases refer to regs->gpr[], so we need all regs */ | |
1289 | if (!FULL_REGS(regs)) | |
3cdfcbfd | 1290 | return -1; |
0016a4cf PM |
1291 | |
1292 | rd = (instr >> 21) & 0x1f; | |
1293 | ra = (instr >> 16) & 0x1f; | |
1294 | rb = (instr >> 11) & 0x1f; | |
930d6288 | 1295 | rc = (instr >> 6) & 0x1f; |
0016a4cf PM |
1296 | |
1297 | switch (opcode) { | |
cf87c3f6 PM |
1298 | #ifdef __powerpc64__ |
1299 | case 2: /* tdi */ | |
1300 | if (rd & trap_compare(regs->gpr[ra], (short) instr)) | |
1301 | goto trap; | |
3cdfcbfd | 1302 | return 1; |
cf87c3f6 PM |
1303 | #endif |
1304 | case 3: /* twi */ | |
1305 | if (rd & trap_compare((int)regs->gpr[ra], (short) instr)) | |
1306 | goto trap; | |
3cdfcbfd | 1307 | return 1; |
cf87c3f6 | 1308 | |
930d6288 SD |
1309 | #ifdef __powerpc64__ |
1310 | case 4: | |
1311 | if (!cpu_has_feature(CPU_FTR_ARCH_300)) | |
1312 | return -1; | |
1313 | ||
1314 | switch (instr & 0x3f) { | |
1315 | case 48: /* maddhd */ | |
1316 | asm volatile(PPC_MADDHD(%0, %1, %2, %3) : | |
1317 | "=r" (op->val) : "r" (regs->gpr[ra]), | |
1318 | "r" (regs->gpr[rb]), "r" (regs->gpr[rc])); | |
1319 | goto compute_done; | |
1320 | ||
1321 | case 49: /* maddhdu */ | |
1322 | asm volatile(PPC_MADDHDU(%0, %1, %2, %3) : | |
1323 | "=r" (op->val) : "r" (regs->gpr[ra]), | |
1324 | "r" (regs->gpr[rb]), "r" (regs->gpr[rc])); | |
1325 | goto compute_done; | |
1326 | ||
1327 | case 51: /* maddld */ | |
1328 | asm volatile(PPC_MADDLD(%0, %1, %2, %3) : | |
1329 | "=r" (op->val) : "r" (regs->gpr[ra]), | |
1330 | "r" (regs->gpr[rb]), "r" (regs->gpr[rc])); | |
1331 | goto compute_done; | |
1332 | } | |
1333 | ||
1334 | /* | |
1335 | * There are other instructions from ISA 3.0 with the same | |
1336 | * primary opcode which do not have emulation support yet. | |
1337 | */ | |
1338 | return -1; | |
1339 | #endif | |
1340 | ||
0016a4cf | 1341 | case 7: /* mulli */ |
3cdfcbfd PM |
1342 | op->val = regs->gpr[ra] * (short) instr; |
1343 | goto compute_done; | |
0016a4cf PM |
1344 | |
1345 | case 8: /* subfic */ | |
1346 | imm = (short) instr; | |
3cdfcbfd PM |
1347 | add_with_carry(regs, op, rd, ~regs->gpr[ra], imm, 1); |
1348 | return 1; | |
0016a4cf PM |
1349 | |
1350 | case 10: /* cmpli */ | |
1351 | imm = (unsigned short) instr; | |
1352 | val = regs->gpr[ra]; | |
1353 | #ifdef __powerpc64__ | |
1354 | if ((rd & 1) == 0) | |
1355 | val = (unsigned int) val; | |
1356 | #endif | |
3cdfcbfd PM |
1357 | do_cmp_unsigned(regs, op, val, imm, rd >> 2); |
1358 | return 1; | |
0016a4cf PM |
1359 | |
1360 | case 11: /* cmpi */ | |
1361 | imm = (short) instr; | |
1362 | val = regs->gpr[ra]; | |
1363 | #ifdef __powerpc64__ | |
1364 | if ((rd & 1) == 0) | |
1365 | val = (int) val; | |
1366 | #endif | |
3cdfcbfd PM |
1367 | do_cmp_signed(regs, op, val, imm, rd >> 2); |
1368 | return 1; | |
0016a4cf PM |
1369 | |
1370 | case 12: /* addic */ | |
1371 | imm = (short) instr; | |
3cdfcbfd PM |
1372 | add_with_carry(regs, op, rd, regs->gpr[ra], imm, 0); |
1373 | return 1; | |
0016a4cf PM |
1374 | |
1375 | case 13: /* addic. */ | |
1376 | imm = (short) instr; | |
3cdfcbfd | 1377 | add_with_carry(regs, op, rd, regs->gpr[ra], imm, 0); |
ad47ff3e | 1378 | set_cr0(regs, op); |
3cdfcbfd | 1379 | return 1; |
0016a4cf PM |
1380 | |
1381 | case 14: /* addi */ | |
1382 | imm = (short) instr; | |
1383 | if (ra) | |
1384 | imm += regs->gpr[ra]; | |
3cdfcbfd PM |
1385 | op->val = imm; |
1386 | goto compute_done; | |
0016a4cf PM |
1387 | |
1388 | case 15: /* addis */ | |
1389 | imm = ((short) instr) << 16; | |
1390 | if (ra) | |
1391 | imm += regs->gpr[ra]; | |
3cdfcbfd PM |
1392 | op->val = imm; |
1393 | goto compute_done; | |
0016a4cf | 1394 | |
958465ee PM |
1395 | case 19: |
1396 | if (((instr >> 1) & 0x1f) == 2) { | |
1397 | /* addpcis */ | |
1398 | imm = (short) (instr & 0xffc1); /* d0 + d2 fields */ | |
1399 | imm |= (instr >> 15) & 0x3e; /* d1 field */ | |
1400 | op->val = regs->nip + (imm << 16) + 4; | |
1401 | goto compute_done; | |
1402 | } | |
1403 | op->type = UNKNOWN; | |
1404 | return 0; | |
1405 | ||
0016a4cf PM |
1406 | case 20: /* rlwimi */ |
1407 | mb = (instr >> 6) & 0x1f; | |
1408 | me = (instr >> 1) & 0x1f; | |
1409 | val = DATA32(regs->gpr[rd]); | |
1410 | imm = MASK32(mb, me); | |
3cdfcbfd | 1411 | op->val = (regs->gpr[ra] & ~imm) | (ROTATE(val, rb) & imm); |
0016a4cf PM |
1412 | goto logical_done; |
1413 | ||
1414 | case 21: /* rlwinm */ | |
1415 | mb = (instr >> 6) & 0x1f; | |
1416 | me = (instr >> 1) & 0x1f; | |
1417 | val = DATA32(regs->gpr[rd]); | |
3cdfcbfd | 1418 | op->val = ROTATE(val, rb) & MASK32(mb, me); |
0016a4cf PM |
1419 | goto logical_done; |
1420 | ||
1421 | case 23: /* rlwnm */ | |
1422 | mb = (instr >> 6) & 0x1f; | |
1423 | me = (instr >> 1) & 0x1f; | |
1424 | rb = regs->gpr[rb] & 0x1f; | |
1425 | val = DATA32(regs->gpr[rd]); | |
3cdfcbfd | 1426 | op->val = ROTATE(val, rb) & MASK32(mb, me); |
0016a4cf PM |
1427 | goto logical_done; |
1428 | ||
1429 | case 24: /* ori */ | |
3cdfcbfd PM |
1430 | op->val = regs->gpr[rd] | (unsigned short) instr; |
1431 | goto logical_done_nocc; | |
0016a4cf PM |
1432 | |
1433 | case 25: /* oris */ | |
1434 | imm = (unsigned short) instr; | |
3cdfcbfd PM |
1435 | op->val = regs->gpr[rd] | (imm << 16); |
1436 | goto logical_done_nocc; | |
0016a4cf PM |
1437 | |
1438 | case 26: /* xori */ | |
3cdfcbfd PM |
1439 | op->val = regs->gpr[rd] ^ (unsigned short) instr; |
1440 | goto logical_done_nocc; | |
0016a4cf PM |
1441 | |
1442 | case 27: /* xoris */ | |
1443 | imm = (unsigned short) instr; | |
3cdfcbfd PM |
1444 | op->val = regs->gpr[rd] ^ (imm << 16); |
1445 | goto logical_done_nocc; | |
0016a4cf PM |
1446 | |
1447 | case 28: /* andi. */ | |
3cdfcbfd | 1448 | op->val = regs->gpr[rd] & (unsigned short) instr; |
ad47ff3e | 1449 | set_cr0(regs, op); |
3cdfcbfd | 1450 | goto logical_done_nocc; |
0016a4cf PM |
1451 | |
1452 | case 29: /* andis. */ | |
1453 | imm = (unsigned short) instr; | |
3cdfcbfd | 1454 | op->val = regs->gpr[rd] & (imm << 16); |
ad47ff3e | 1455 | set_cr0(regs, op); |
3cdfcbfd | 1456 | goto logical_done_nocc; |
0016a4cf PM |
1457 | |
1458 | #ifdef __powerpc64__ | |
1459 | case 30: /* rld* */ | |
1460 | mb = ((instr >> 6) & 0x1f) | (instr & 0x20); | |
1461 | val = regs->gpr[rd]; | |
1462 | if ((instr & 0x10) == 0) { | |
1463 | sh = rb | ((instr & 2) << 4); | |
1464 | val = ROTATE(val, sh); | |
1465 | switch ((instr >> 2) & 3) { | |
1466 | case 0: /* rldicl */ | |
3cdfcbfd PM |
1467 | val &= MASK64_L(mb); |
1468 | break; | |
0016a4cf | 1469 | case 1: /* rldicr */ |
3cdfcbfd PM |
1470 | val &= MASK64_R(mb); |
1471 | break; | |
0016a4cf | 1472 | case 2: /* rldic */ |
3cdfcbfd PM |
1473 | val &= MASK64(mb, 63 - sh); |
1474 | break; | |
0016a4cf PM |
1475 | case 3: /* rldimi */ |
1476 | imm = MASK64(mb, 63 - sh); | |
3cdfcbfd | 1477 | val = (regs->gpr[ra] & ~imm) | |
0016a4cf | 1478 | (val & imm); |
0016a4cf | 1479 | } |
3cdfcbfd PM |
1480 | op->val = val; |
1481 | goto logical_done; | |
0016a4cf PM |
1482 | } else { |
1483 | sh = regs->gpr[rb] & 0x3f; | |
1484 | val = ROTATE(val, sh); | |
1485 | switch ((instr >> 1) & 7) { | |
1486 | case 0: /* rldcl */ | |
3cdfcbfd | 1487 | op->val = val & MASK64_L(mb); |
0016a4cf PM |
1488 | goto logical_done; |
1489 | case 1: /* rldcr */ | |
3cdfcbfd | 1490 | op->val = val & MASK64_R(mb); |
0016a4cf PM |
1491 | goto logical_done; |
1492 | } | |
14cf11af | 1493 | } |
0016a4cf | 1494 | #endif |
3cdfcbfd PM |
1495 | op->type = UNKNOWN; /* illegal instruction */ |
1496 | return 0; | |
0016a4cf | 1497 | |
14cf11af | 1498 | case 31: |
f1bbb99f PM |
1499 | /* isel occupies 32 minor opcodes */ |
1500 | if (((instr >> 1) & 0x1f) == 15) { | |
1501 | mb = (instr >> 6) & 0x1f; /* bc field */ | |
1502 | val = (regs->ccr >> (31 - mb)) & 1; | |
1503 | val2 = (ra) ? regs->gpr[ra] : 0; | |
1504 | ||
1505 | op->val = (val) ? val2 : regs->gpr[rb]; | |
1506 | goto compute_done; | |
1507 | } | |
1508 | ||
0016a4cf | 1509 | switch ((instr >> 1) & 0x3ff) { |
cf87c3f6 PM |
1510 | case 4: /* tw */ |
1511 | if (rd == 0x1f || | |
1512 | (rd & trap_compare((int)regs->gpr[ra], | |
1513 | (int)regs->gpr[rb]))) | |
1514 | goto trap; | |
3cdfcbfd | 1515 | return 1; |
cf87c3f6 PM |
1516 | #ifdef __powerpc64__ |
1517 | case 68: /* td */ | |
1518 | if (rd & trap_compare(regs->gpr[ra], regs->gpr[rb])) | |
1519 | goto trap; | |
3cdfcbfd | 1520 | return 1; |
cf87c3f6 | 1521 | #endif |
0016a4cf PM |
1522 | case 83: /* mfmsr */ |
1523 | if (regs->msr & MSR_PR) | |
be96f633 PM |
1524 | goto priv; |
1525 | op->type = MFMSR; | |
1526 | op->reg = rd; | |
1527 | return 0; | |
0016a4cf PM |
1528 | case 146: /* mtmsr */ |
1529 | if (regs->msr & MSR_PR) | |
be96f633 PM |
1530 | goto priv; |
1531 | op->type = MTMSR; | |
1532 | op->reg = rd; | |
1533 | op->val = 0xffffffff & ~(MSR_ME | MSR_LE); | |
1534 | return 0; | |
c032524f | 1535 | #ifdef CONFIG_PPC64 |
0016a4cf | 1536 | case 178: /* mtmsrd */ |
0016a4cf | 1537 | if (regs->msr & MSR_PR) |
be96f633 PM |
1538 | goto priv; |
1539 | op->type = MTMSR; | |
1540 | op->reg = rd; | |
1541 | /* only MSR_EE and MSR_RI get changed if bit 15 set */ | |
1542 | /* mtmsrd doesn't change MSR_HV, MSR_ME or MSR_LE */ | |
1543 | imm = (instr & 0x10000)? 0x8002: 0xefffffffffffeffeUL; | |
1544 | op->val = imm; | |
1545 | return 0; | |
c032524f | 1546 | #endif |
be96f633 | 1547 | |
0016a4cf | 1548 | case 19: /* mfcr */ |
3cdfcbfd | 1549 | imm = 0xffffffffUL; |
64e756c5 AB |
1550 | if ((instr >> 20) & 1) { |
1551 | imm = 0xf0000000UL; | |
1552 | for (sh = 0; sh < 8; ++sh) { | |
3cdfcbfd | 1553 | if (instr & (0x80000 >> sh)) |
64e756c5 | 1554 | break; |
64e756c5 AB |
1555 | imm >>= 4; |
1556 | } | |
64e756c5 | 1557 | } |
3cdfcbfd PM |
1558 | op->val = regs->ccr & imm; |
1559 | goto compute_done; | |
0016a4cf PM |
1560 | |
1561 | case 144: /* mtcrf */ | |
3cdfcbfd | 1562 | op->type = COMPUTE + SETCC; |
0016a4cf PM |
1563 | imm = 0xf0000000UL; |
1564 | val = regs->gpr[rd]; | |
5bcaa4cc | 1565 | op->ccval = regs->ccr; |
0016a4cf PM |
1566 | for (sh = 0; sh < 8; ++sh) { |
1567 | if (instr & (0x80000 >> sh)) | |
5bcaa4cc | 1568 | op->ccval = (op->ccval & ~imm) | |
0016a4cf PM |
1569 | (val & imm); |
1570 | imm >>= 4; | |
1571 | } | |
3cdfcbfd | 1572 | return 1; |
0016a4cf PM |
1573 | |
1574 | case 339: /* mfspr */ | |
be96f633 | 1575 | spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0); |
3cdfcbfd PM |
1576 | op->type = MFSPR; |
1577 | op->reg = rd; | |
1578 | op->spr = spr; | |
1579 | if (spr == SPRN_XER || spr == SPRN_LR || | |
1580 | spr == SPRN_CTR) | |
1581 | return 1; | |
1582 | return 0; | |
0016a4cf PM |
1583 | |
1584 | case 467: /* mtspr */ | |
be96f633 | 1585 | spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0); |
3cdfcbfd PM |
1586 | op->type = MTSPR; |
1587 | op->val = regs->gpr[rd]; | |
1588 | op->spr = spr; | |
1589 | if (spr == SPRN_XER || spr == SPRN_LR || | |
1590 | spr == SPRN_CTR) | |
1591 | return 1; | |
1592 | return 0; | |
0016a4cf PM |
1593 | |
1594 | /* | |
1595 | * Compare instructions | |
1596 | */ | |
1597 | case 0: /* cmp */ | |
1598 | val = regs->gpr[ra]; | |
1599 | val2 = regs->gpr[rb]; | |
1600 | #ifdef __powerpc64__ | |
1601 | if ((rd & 1) == 0) { | |
1602 | /* word (32-bit) compare */ | |
1603 | val = (int) val; | |
1604 | val2 = (int) val2; | |
1605 | } | |
1606 | #endif | |
3cdfcbfd PM |
1607 | do_cmp_signed(regs, op, val, val2, rd >> 2); |
1608 | return 1; | |
0016a4cf PM |
1609 | |
1610 | case 32: /* cmpl */ | |
1611 | val = regs->gpr[ra]; | |
1612 | val2 = regs->gpr[rb]; | |
1613 | #ifdef __powerpc64__ | |
1614 | if ((rd & 1) == 0) { | |
1615 | /* word (32-bit) compare */ | |
1616 | val = (unsigned int) val; | |
1617 | val2 = (unsigned int) val2; | |
1618 | } | |
1619 | #endif | |
3cdfcbfd PM |
1620 | do_cmp_unsigned(regs, op, val, val2, rd >> 2); |
1621 | return 1; | |
0016a4cf | 1622 | |
02c0f62a | 1623 | case 508: /* cmpb */ |
3cdfcbfd PM |
1624 | do_cmpb(regs, op, regs->gpr[rd], regs->gpr[rb]); |
1625 | goto logical_done_nocc; | |
02c0f62a | 1626 | |
0016a4cf PM |
1627 | /* |
1628 | * Arithmetic instructions | |
1629 | */ | |
1630 | case 8: /* subfc */ | |
3cdfcbfd | 1631 | add_with_carry(regs, op, rd, ~regs->gpr[ra], |
0016a4cf PM |
1632 | regs->gpr[rb], 1); |
1633 | goto arith_done; | |
1634 | #ifdef __powerpc64__ | |
1635 | case 9: /* mulhdu */ | |
3cdfcbfd | 1636 | asm("mulhdu %0,%1,%2" : "=r" (op->val) : |
0016a4cf PM |
1637 | "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); |
1638 | goto arith_done; | |
1639 | #endif | |
1640 | case 10: /* addc */ | |
3cdfcbfd | 1641 | add_with_carry(regs, op, rd, regs->gpr[ra], |
0016a4cf PM |
1642 | regs->gpr[rb], 0); |
1643 | goto arith_done; | |
1644 | ||
1645 | case 11: /* mulhwu */ | |
3cdfcbfd | 1646 | asm("mulhwu %0,%1,%2" : "=r" (op->val) : |
0016a4cf PM |
1647 | "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); |
1648 | goto arith_done; | |
1649 | ||
1650 | case 40: /* subf */ | |
3cdfcbfd | 1651 | op->val = regs->gpr[rb] - regs->gpr[ra]; |
0016a4cf PM |
1652 | goto arith_done; |
1653 | #ifdef __powerpc64__ | |
1654 | case 73: /* mulhd */ | |
3cdfcbfd | 1655 | asm("mulhd %0,%1,%2" : "=r" (op->val) : |
0016a4cf PM |
1656 | "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); |
1657 | goto arith_done; | |
1658 | #endif | |
1659 | case 75: /* mulhw */ | |
3cdfcbfd | 1660 | asm("mulhw %0,%1,%2" : "=r" (op->val) : |
0016a4cf PM |
1661 | "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); |
1662 | goto arith_done; | |
1663 | ||
1664 | case 104: /* neg */ | |
3cdfcbfd | 1665 | op->val = -regs->gpr[ra]; |
0016a4cf PM |
1666 | goto arith_done; |
1667 | ||
1668 | case 136: /* subfe */ | |
3cdfcbfd PM |
1669 | add_with_carry(regs, op, rd, ~regs->gpr[ra], |
1670 | regs->gpr[rb], regs->xer & XER_CA); | |
0016a4cf PM |
1671 | goto arith_done; |
1672 | ||
1673 | case 138: /* adde */ | |
3cdfcbfd PM |
1674 | add_with_carry(regs, op, rd, regs->gpr[ra], |
1675 | regs->gpr[rb], regs->xer & XER_CA); | |
0016a4cf PM |
1676 | goto arith_done; |
1677 | ||
1678 | case 200: /* subfze */ | |
3cdfcbfd | 1679 | add_with_carry(regs, op, rd, ~regs->gpr[ra], 0L, |
0016a4cf PM |
1680 | regs->xer & XER_CA); |
1681 | goto arith_done; | |
1682 | ||
1683 | case 202: /* addze */ | |
3cdfcbfd | 1684 | add_with_carry(regs, op, rd, regs->gpr[ra], 0L, |
0016a4cf PM |
1685 | regs->xer & XER_CA); |
1686 | goto arith_done; | |
1687 | ||
1688 | case 232: /* subfme */ | |
3cdfcbfd | 1689 | add_with_carry(regs, op, rd, ~regs->gpr[ra], -1L, |
0016a4cf PM |
1690 | regs->xer & XER_CA); |
1691 | goto arith_done; | |
1692 | #ifdef __powerpc64__ | |
1693 | case 233: /* mulld */ | |
3cdfcbfd | 1694 | op->val = regs->gpr[ra] * regs->gpr[rb]; |
0016a4cf PM |
1695 | goto arith_done; |
1696 | #endif | |
1697 | case 234: /* addme */ | |
3cdfcbfd | 1698 | add_with_carry(regs, op, rd, regs->gpr[ra], -1L, |
0016a4cf PM |
1699 | regs->xer & XER_CA); |
1700 | goto arith_done; | |
1701 | ||
1702 | case 235: /* mullw */ | |
1575fe06 AB |
1703 | op->val = (long)(int) regs->gpr[ra] * |
1704 | (int) regs->gpr[rb]; | |
1705 | ||
0016a4cf | 1706 | goto arith_done; |
6324320d SD |
1707 | #ifdef __powerpc64__ |
1708 | case 265: /* modud */ | |
1709 | if (!cpu_has_feature(CPU_FTR_ARCH_300)) | |
1710 | return -1; | |
1711 | op->val = regs->gpr[ra] % regs->gpr[rb]; | |
1712 | goto compute_done; | |
1713 | #endif | |
0016a4cf | 1714 | case 266: /* add */ |
3cdfcbfd | 1715 | op->val = regs->gpr[ra] + regs->gpr[rb]; |
0016a4cf | 1716 | goto arith_done; |
6c180071 PM |
1717 | |
1718 | case 267: /* moduw */ | |
1719 | if (!cpu_has_feature(CPU_FTR_ARCH_300)) | |
1720 | return -1; | |
1721 | op->val = (unsigned int) regs->gpr[ra] % | |
1722 | (unsigned int) regs->gpr[rb]; | |
1723 | goto compute_done; | |
0016a4cf PM |
1724 | #ifdef __powerpc64__ |
1725 | case 457: /* divdu */ | |
3cdfcbfd | 1726 | op->val = regs->gpr[ra] / regs->gpr[rb]; |
0016a4cf PM |
1727 | goto arith_done; |
1728 | #endif | |
1729 | case 459: /* divwu */ | |
3cdfcbfd | 1730 | op->val = (unsigned int) regs->gpr[ra] / |
0016a4cf PM |
1731 | (unsigned int) regs->gpr[rb]; |
1732 | goto arith_done; | |
1733 | #ifdef __powerpc64__ | |
1734 | case 489: /* divd */ | |
3cdfcbfd | 1735 | op->val = (long int) regs->gpr[ra] / |
0016a4cf PM |
1736 | (long int) regs->gpr[rb]; |
1737 | goto arith_done; | |
1738 | #endif | |
1739 | case 491: /* divw */ | |
3cdfcbfd | 1740 | op->val = (int) regs->gpr[ra] / |
0016a4cf PM |
1741 | (int) regs->gpr[rb]; |
1742 | goto arith_done; | |
1743 | ||
a23987ef SD |
1744 | case 755: /* darn */ |
1745 | if (!cpu_has_feature(CPU_FTR_ARCH_300)) | |
1746 | return -1; | |
1747 | switch (ra & 0x3) { | |
1748 | case 0: | |
1749 | /* 32-bit conditioned */ | |
1750 | asm volatile(PPC_DARN(%0, 0) : "=r" (op->val)); | |
1751 | goto compute_done; | |
1752 | ||
1753 | case 1: | |
1754 | /* 64-bit conditioned */ | |
1755 | asm volatile(PPC_DARN(%0, 1) : "=r" (op->val)); | |
1756 | goto compute_done; | |
1757 | ||
1758 | case 2: | |
1759 | /* 64-bit raw */ | |
1760 | asm volatile(PPC_DARN(%0, 2) : "=r" (op->val)); | |
1761 | goto compute_done; | |
1762 | } | |
1763 | ||
1764 | return -1; | |
6324320d SD |
1765 | #ifdef __powerpc64__ |
1766 | case 777: /* modsd */ | |
1767 | if (!cpu_has_feature(CPU_FTR_ARCH_300)) | |
1768 | return -1; | |
1769 | op->val = (long int) regs->gpr[ra] % | |
1770 | (long int) regs->gpr[rb]; | |
1771 | goto compute_done; | |
1772 | #endif | |
6c180071 PM |
1773 | case 779: /* modsw */ |
1774 | if (!cpu_has_feature(CPU_FTR_ARCH_300)) | |
1775 | return -1; | |
1776 | op->val = (int) regs->gpr[ra] % | |
1777 | (int) regs->gpr[rb]; | |
1778 | goto compute_done; | |
1779 | ||
0016a4cf PM |
1780 | |
1781 | /* | |
1782 | * Logical instructions | |
1783 | */ | |
1784 | case 26: /* cntlzw */ | |
b0490a04 SD |
1785 | val = (unsigned int) regs->gpr[rd]; |
1786 | op->val = ( val ? __builtin_clz(val) : 32 ); | |
0016a4cf PM |
1787 | goto logical_done; |
1788 | #ifdef __powerpc64__ | |
1789 | case 58: /* cntlzd */ | |
b0490a04 SD |
1790 | val = regs->gpr[rd]; |
1791 | op->val = ( val ? __builtin_clzl(val) : 64 ); | |
0016a4cf PM |
1792 | goto logical_done; |
1793 | #endif | |
1794 | case 28: /* and */ | |
3cdfcbfd | 1795 | op->val = regs->gpr[rd] & regs->gpr[rb]; |
0016a4cf PM |
1796 | goto logical_done; |
1797 | ||
1798 | case 60: /* andc */ | |
3cdfcbfd | 1799 | op->val = regs->gpr[rd] & ~regs->gpr[rb]; |
0016a4cf PM |
1800 | goto logical_done; |
1801 | ||
dcbd19b4 | 1802 | case 122: /* popcntb */ |
3cdfcbfd | 1803 | do_popcnt(regs, op, regs->gpr[rd], 8); |
5762e083 | 1804 | goto logical_done_nocc; |
dcbd19b4 | 1805 | |
0016a4cf | 1806 | case 124: /* nor */ |
3cdfcbfd | 1807 | op->val = ~(regs->gpr[rd] | regs->gpr[rb]); |
0016a4cf | 1808 | goto logical_done; |
2c979c48 MB |
1809 | |
1810 | case 154: /* prtyw */ | |
3cdfcbfd | 1811 | do_prty(regs, op, regs->gpr[rd], 32); |
5762e083 | 1812 | goto logical_done_nocc; |
2c979c48 MB |
1813 | |
1814 | case 186: /* prtyd */ | |
3cdfcbfd | 1815 | do_prty(regs, op, regs->gpr[rd], 64); |
5762e083 | 1816 | goto logical_done_nocc; |
f312793d MB |
1817 | #ifdef CONFIG_PPC64 |
1818 | case 252: /* bpermd */ | |
3cdfcbfd | 1819 | do_bpermd(regs, op, regs->gpr[rd], regs->gpr[rb]); |
5762e083 | 1820 | goto logical_done_nocc; |
f312793d | 1821 | #endif |
0016a4cf | 1822 | case 284: /* xor */ |
3cdfcbfd | 1823 | op->val = ~(regs->gpr[rd] ^ regs->gpr[rb]); |
0016a4cf PM |
1824 | goto logical_done; |
1825 | ||
1826 | case 316: /* xor */ | |
3cdfcbfd | 1827 | op->val = regs->gpr[rd] ^ regs->gpr[rb]; |
0016a4cf PM |
1828 | goto logical_done; |
1829 | ||
dcbd19b4 | 1830 | case 378: /* popcntw */ |
3cdfcbfd | 1831 | do_popcnt(regs, op, regs->gpr[rd], 32); |
5762e083 | 1832 | goto logical_done_nocc; |
dcbd19b4 | 1833 | |
0016a4cf | 1834 | case 412: /* orc */ |
3cdfcbfd | 1835 | op->val = regs->gpr[rd] | ~regs->gpr[rb]; |
0016a4cf PM |
1836 | goto logical_done; |
1837 | ||
1838 | case 444: /* or */ | |
3cdfcbfd | 1839 | op->val = regs->gpr[rd] | regs->gpr[rb]; |
0016a4cf PM |
1840 | goto logical_done; |
1841 | ||
1842 | case 476: /* nand */ | |
3cdfcbfd | 1843 | op->val = ~(regs->gpr[rd] & regs->gpr[rb]); |
0016a4cf | 1844 | goto logical_done; |
dcbd19b4 MB |
1845 | #ifdef CONFIG_PPC64 |
1846 | case 506: /* popcntd */ | |
3cdfcbfd | 1847 | do_popcnt(regs, op, regs->gpr[rd], 64); |
5762e083 | 1848 | goto logical_done_nocc; |
32628b5c SD |
1849 | #endif |
1850 | case 538: /* cnttzw */ | |
1851 | if (!cpu_has_feature(CPU_FTR_ARCH_300)) | |
1852 | return -1; | |
1853 | val = (unsigned int) regs->gpr[rd]; | |
1854 | op->val = (val ? __builtin_ctz(val) : 32); | |
1855 | goto logical_done; | |
1856 | #ifdef __powerpc64__ | |
1857 | case 570: /* cnttzd */ | |
1858 | if (!cpu_has_feature(CPU_FTR_ARCH_300)) | |
1859 | return -1; | |
1860 | val = regs->gpr[rd]; | |
1861 | op->val = (val ? __builtin_ctzl(val) : 64); | |
1862 | goto logical_done; | |
dcbd19b4 | 1863 | #endif |
0016a4cf | 1864 | case 922: /* extsh */ |
3cdfcbfd | 1865 | op->val = (signed short) regs->gpr[rd]; |
0016a4cf PM |
1866 | goto logical_done; |
1867 | ||
1868 | case 954: /* extsb */ | |
3cdfcbfd | 1869 | op->val = (signed char) regs->gpr[rd]; |
0016a4cf PM |
1870 | goto logical_done; |
1871 | #ifdef __powerpc64__ | |
1872 | case 986: /* extsw */ | |
3cdfcbfd | 1873 | op->val = (signed int) regs->gpr[rd]; |
0016a4cf PM |
1874 | goto logical_done; |
1875 | #endif | |
1876 | ||
1877 | /* | |
1878 | * Shift instructions | |
1879 | */ | |
1880 | case 24: /* slw */ | |
1881 | sh = regs->gpr[rb] & 0x3f; | |
1882 | if (sh < 32) | |
3cdfcbfd | 1883 | op->val = (regs->gpr[rd] << sh) & 0xffffffffUL; |
0016a4cf | 1884 | else |
3cdfcbfd | 1885 | op->val = 0; |
0016a4cf PM |
1886 | goto logical_done; |
1887 | ||
1888 | case 536: /* srw */ | |
1889 | sh = regs->gpr[rb] & 0x3f; | |
1890 | if (sh < 32) | |
3cdfcbfd | 1891 | op->val = (regs->gpr[rd] & 0xffffffffUL) >> sh; |
0016a4cf | 1892 | else |
3cdfcbfd | 1893 | op->val = 0; |
0016a4cf PM |
1894 | goto logical_done; |
1895 | ||
1896 | case 792: /* sraw */ | |
3cdfcbfd | 1897 | op->type = COMPUTE + SETREG + SETXER; |
0016a4cf PM |
1898 | sh = regs->gpr[rb] & 0x3f; |
1899 | ival = (signed int) regs->gpr[rd]; | |
3cdfcbfd PM |
1900 | op->val = ival >> (sh < 32 ? sh : 31); |
1901 | op->xerval = regs->xer; | |
e698b966 | 1902 | if (ival < 0 && (sh >= 32 || (ival & ((1ul << sh) - 1)) != 0)) |
3cdfcbfd | 1903 | op->xerval |= XER_CA; |
0016a4cf | 1904 | else |
3cdfcbfd | 1905 | op->xerval &= ~XER_CA; |
0a75aff1 | 1906 | set_ca32(op, op->xerval & XER_CA); |
0016a4cf PM |
1907 | goto logical_done; |
1908 | ||
1909 | case 824: /* srawi */ | |
3cdfcbfd | 1910 | op->type = COMPUTE + SETREG + SETXER; |
0016a4cf PM |
1911 | sh = rb; |
1912 | ival = (signed int) regs->gpr[rd]; | |
3cdfcbfd PM |
1913 | op->val = ival >> sh; |
1914 | op->xerval = regs->xer; | |
e698b966 | 1915 | if (ival < 0 && (ival & ((1ul << sh) - 1)) != 0) |
3cdfcbfd | 1916 | op->xerval |= XER_CA; |
0016a4cf | 1917 | else |
3cdfcbfd | 1918 | op->xerval &= ~XER_CA; |
0a75aff1 | 1919 | set_ca32(op, op->xerval & XER_CA); |
0016a4cf PM |
1920 | goto logical_done; |
1921 | ||
1922 | #ifdef __powerpc64__ | |
1923 | case 27: /* sld */ | |
e698b966 | 1924 | sh = regs->gpr[rb] & 0x7f; |
0016a4cf | 1925 | if (sh < 64) |
3cdfcbfd | 1926 | op->val = regs->gpr[rd] << sh; |
0016a4cf | 1927 | else |
3cdfcbfd | 1928 | op->val = 0; |
0016a4cf PM |
1929 | goto logical_done; |
1930 | ||
1931 | case 539: /* srd */ | |
1932 | sh = regs->gpr[rb] & 0x7f; | |
1933 | if (sh < 64) | |
3cdfcbfd | 1934 | op->val = regs->gpr[rd] >> sh; |
0016a4cf | 1935 | else |
3cdfcbfd | 1936 | op->val = 0; |
0016a4cf PM |
1937 | goto logical_done; |
1938 | ||
1939 | case 794: /* srad */ | |
3cdfcbfd | 1940 | op->type = COMPUTE + SETREG + SETXER; |
0016a4cf PM |
1941 | sh = regs->gpr[rb] & 0x7f; |
1942 | ival = (signed long int) regs->gpr[rd]; | |
3cdfcbfd PM |
1943 | op->val = ival >> (sh < 64 ? sh : 63); |
1944 | op->xerval = regs->xer; | |
e698b966 | 1945 | if (ival < 0 && (sh >= 64 || (ival & ((1ul << sh) - 1)) != 0)) |
3cdfcbfd | 1946 | op->xerval |= XER_CA; |
0016a4cf | 1947 | else |
3cdfcbfd | 1948 | op->xerval &= ~XER_CA; |
0a75aff1 | 1949 | set_ca32(op, op->xerval & XER_CA); |
0016a4cf PM |
1950 | goto logical_done; |
1951 | ||
1952 | case 826: /* sradi with sh_5 = 0 */ | |
1953 | case 827: /* sradi with sh_5 = 1 */ | |
3cdfcbfd | 1954 | op->type = COMPUTE + SETREG + SETXER; |
0016a4cf PM |
1955 | sh = rb | ((instr & 2) << 4); |
1956 | ival = (signed long int) regs->gpr[rd]; | |
3cdfcbfd PM |
1957 | op->val = ival >> sh; |
1958 | op->xerval = regs->xer; | |
e698b966 | 1959 | if (ival < 0 && (ival & ((1ul << sh) - 1)) != 0) |
3cdfcbfd | 1960 | op->xerval |= XER_CA; |
0016a4cf | 1961 | else |
3cdfcbfd | 1962 | op->xerval &= ~XER_CA; |
0a75aff1 | 1963 | set_ca32(op, op->xerval & XER_CA); |
0016a4cf | 1964 | goto logical_done; |
3e751acb SD |
1965 | |
1966 | case 890: /* extswsli with sh_5 = 0 */ | |
1967 | case 891: /* extswsli with sh_5 = 1 */ | |
1968 | if (!cpu_has_feature(CPU_FTR_ARCH_300)) | |
1969 | return -1; | |
1970 | op->type = COMPUTE + SETREG; | |
1971 | sh = rb | ((instr & 2) << 4); | |
1972 | val = (signed int) regs->gpr[rd]; | |
1973 | if (sh) | |
1974 | op->val = ROTATE(val, sh) & MASK64(0, 63 - sh); | |
1975 | else | |
1976 | op->val = val; | |
1977 | goto logical_done; | |
1978 | ||
0016a4cf PM |
1979 | #endif /* __powerpc64__ */ |
1980 | ||
1981 | /* | |
1982 | * Cache instructions | |
1983 | */ | |
1984 | case 54: /* dcbst */ | |
be96f633 PM |
1985 | op->type = MKOP(CACHEOP, DCBST, 0); |
1986 | op->ea = xform_ea(instr, regs); | |
1987 | return 0; | |
0016a4cf PM |
1988 | |
1989 | case 86: /* dcbf */ | |
be96f633 PM |
1990 | op->type = MKOP(CACHEOP, DCBF, 0); |
1991 | op->ea = xform_ea(instr, regs); | |
1992 | return 0; | |
0016a4cf PM |
1993 | |
1994 | case 246: /* dcbtst */ | |
be96f633 PM |
1995 | op->type = MKOP(CACHEOP, DCBTST, 0); |
1996 | op->ea = xform_ea(instr, regs); | |
1997 | op->reg = rd; | |
1998 | return 0; | |
0016a4cf PM |
1999 | |
2000 | case 278: /* dcbt */ | |
be96f633 PM |
2001 | op->type = MKOP(CACHEOP, DCBTST, 0); |
2002 | op->ea = xform_ea(instr, regs); | |
2003 | op->reg = rd; | |
2004 | return 0; | |
cf87c3f6 PM |
2005 | |
2006 | case 982: /* icbi */ | |
2007 | op->type = MKOP(CACHEOP, ICBI, 0); | |
2008 | op->ea = xform_ea(instr, regs); | |
2009 | return 0; | |
b2543f7b PM |
2010 | |
2011 | case 1014: /* dcbz */ | |
2012 | op->type = MKOP(CACHEOP, DCBZ, 0); | |
2013 | op->ea = xform_ea(instr, regs); | |
2014 | return 0; | |
14cf11af | 2015 | } |
0016a4cf | 2016 | break; |
14cf11af | 2017 | } |
0016a4cf | 2018 | |
350779a2 PM |
2019 | /* |
2020 | * Loads and stores. | |
2021 | */ | |
be96f633 PM |
2022 | op->type = UNKNOWN; |
2023 | op->update_reg = ra; | |
2024 | op->reg = rd; | |
2025 | op->val = regs->gpr[rd]; | |
2026 | u = (instr >> 20) & UPDATE; | |
350779a2 | 2027 | op->vsx_flags = 0; |
0016a4cf PM |
2028 | |
2029 | switch (opcode) { | |
2030 | case 31: | |
be96f633 PM |
2031 | u = instr & UPDATE; |
2032 | op->ea = xform_ea(instr, regs); | |
0016a4cf PM |
2033 | switch ((instr >> 1) & 0x3ff) { |
2034 | case 20: /* lwarx */ | |
be96f633 PM |
2035 | op->type = MKOP(LARX, 0, 4); |
2036 | break; | |
0016a4cf PM |
2037 | |
2038 | case 150: /* stwcx. */ | |
be96f633 PM |
2039 | op->type = MKOP(STCX, 0, 4); |
2040 | break; | |
0016a4cf PM |
2041 | |
2042 | #ifdef __powerpc64__ | |
2043 | case 84: /* ldarx */ | |
be96f633 PM |
2044 | op->type = MKOP(LARX, 0, 8); |
2045 | break; | |
0016a4cf PM |
2046 | |
2047 | case 214: /* stdcx. */ | |
be96f633 PM |
2048 | op->type = MKOP(STCX, 0, 8); |
2049 | break; | |
0016a4cf | 2050 | |
350779a2 PM |
2051 | case 52: /* lbarx */ |
2052 | op->type = MKOP(LARX, 0, 1); | |
2053 | break; | |
2054 | ||
2055 | case 694: /* stbcx. */ | |
2056 | op->type = MKOP(STCX, 0, 1); | |
2057 | break; | |
2058 | ||
2059 | case 116: /* lharx */ | |
2060 | op->type = MKOP(LARX, 0, 2); | |
2061 | break; | |
2062 | ||
2063 | case 726: /* sthcx. */ | |
2064 | op->type = MKOP(STCX, 0, 2); | |
2065 | break; | |
2066 | ||
2067 | case 276: /* lqarx */ | |
2068 | if (!((rd & 1) || rd == ra || rd == rb)) | |
2069 | op->type = MKOP(LARX, 0, 16); | |
2070 | break; | |
2071 | ||
2072 | case 182: /* stqcx. */ | |
2073 | if (!(rd & 1)) | |
2074 | op->type = MKOP(STCX, 0, 16); | |
be96f633 | 2075 | break; |
0016a4cf PM |
2076 | #endif |
2077 | ||
2078 | case 23: /* lwzx */ | |
2079 | case 55: /* lwzux */ | |
be96f633 PM |
2080 | op->type = MKOP(LOAD, u, 4); |
2081 | break; | |
0016a4cf PM |
2082 | |
2083 | case 87: /* lbzx */ | |
2084 | case 119: /* lbzux */ | |
be96f633 PM |
2085 | op->type = MKOP(LOAD, u, 1); |
2086 | break; | |
0016a4cf PM |
2087 | |
2088 | #ifdef CONFIG_ALTIVEC | |
e61ccc7b PM |
2089 | /* |
2090 | * Note: for the load/store vector element instructions, | |
2091 | * bits of the EA say which field of the VMX register to use. | |
2092 | */ | |
2093 | case 7: /* lvebx */ | |
2094 | op->type = MKOP(LOAD_VMX, 0, 1); | |
2095 | op->element_size = 1; | |
2096 | break; | |
2097 | ||
2098 | case 39: /* lvehx */ | |
2099 | op->type = MKOP(LOAD_VMX, 0, 2); | |
2100 | op->element_size = 2; | |
2101 | break; | |
2102 | ||
2103 | case 71: /* lvewx */ | |
2104 | op->type = MKOP(LOAD_VMX, 0, 4); | |
2105 | op->element_size = 4; | |
2106 | break; | |
2107 | ||
0016a4cf PM |
2108 | case 103: /* lvx */ |
2109 | case 359: /* lvxl */ | |
be96f633 | 2110 | op->type = MKOP(LOAD_VMX, 0, 16); |
350779a2 | 2111 | op->element_size = 16; |
be96f633 | 2112 | break; |
0016a4cf | 2113 | |
e61ccc7b PM |
2114 | case 135: /* stvebx */ |
2115 | op->type = MKOP(STORE_VMX, 0, 1); | |
2116 | op->element_size = 1; | |
2117 | break; | |
2118 | ||
2119 | case 167: /* stvehx */ | |
2120 | op->type = MKOP(STORE_VMX, 0, 2); | |
2121 | op->element_size = 2; | |
2122 | break; | |
2123 | ||
2124 | case 199: /* stvewx */ | |
2125 | op->type = MKOP(STORE_VMX, 0, 4); | |
2126 | op->element_size = 4; | |
2127 | break; | |
2128 | ||
0016a4cf PM |
2129 | case 231: /* stvx */ |
2130 | case 487: /* stvxl */ | |
be96f633 PM |
2131 | op->type = MKOP(STORE_VMX, 0, 16); |
2132 | break; | |
0016a4cf PM |
2133 | #endif /* CONFIG_ALTIVEC */ |
2134 | ||
2135 | #ifdef __powerpc64__ | |
350779a2 PM |
2136 | case 21: /* ldx */ |
2137 | case 53: /* ldux */ | |
2138 | op->type = MKOP(LOAD, u, 8); | |
2139 | break; | |
2140 | ||
0016a4cf PM |
2141 | case 149: /* stdx */ |
2142 | case 181: /* stdux */ | |
be96f633 PM |
2143 | op->type = MKOP(STORE, u, 8); |
2144 | break; | |
0016a4cf PM |
2145 | #endif |
2146 | ||
2147 | case 151: /* stwx */ | |
2148 | case 183: /* stwux */ | |
be96f633 PM |
2149 | op->type = MKOP(STORE, u, 4); |
2150 | break; | |
0016a4cf PM |
2151 | |
2152 | case 215: /* stbx */ | |
2153 | case 247: /* stbux */ | |
be96f633 PM |
2154 | op->type = MKOP(STORE, u, 1); |
2155 | break; | |
0016a4cf PM |
2156 | |
2157 | case 279: /* lhzx */ | |
2158 | case 311: /* lhzux */ | |
be96f633 PM |
2159 | op->type = MKOP(LOAD, u, 2); |
2160 | break; | |
0016a4cf PM |
2161 | |
2162 | #ifdef __powerpc64__ | |
2163 | case 341: /* lwax */ | |
2164 | case 373: /* lwaux */ | |
be96f633 PM |
2165 | op->type = MKOP(LOAD, SIGNEXT | u, 4); |
2166 | break; | |
0016a4cf PM |
2167 | #endif |
2168 | ||
2169 | case 343: /* lhax */ | |
2170 | case 375: /* lhaux */ | |
be96f633 PM |
2171 | op->type = MKOP(LOAD, SIGNEXT | u, 2); |
2172 | break; | |
0016a4cf PM |
2173 | |
2174 | case 407: /* sthx */ | |
2175 | case 439: /* sthux */ | |
be96f633 PM |
2176 | op->type = MKOP(STORE, u, 2); |
2177 | break; | |
0016a4cf PM |
2178 | |
2179 | #ifdef __powerpc64__ | |
2180 | case 532: /* ldbrx */ | |
be96f633 PM |
2181 | op->type = MKOP(LOAD, BYTEREV, 8); |
2182 | break; | |
0016a4cf PM |
2183 | |
2184 | #endif | |
c9f6f4ed PM |
2185 | case 533: /* lswx */ |
2186 | op->type = MKOP(LOAD_MULTI, 0, regs->xer & 0x7f); | |
2187 | break; | |
0016a4cf PM |
2188 | |
2189 | case 534: /* lwbrx */ | |
be96f633 PM |
2190 | op->type = MKOP(LOAD, BYTEREV, 4); |
2191 | break; | |
0016a4cf | 2192 | |
c9f6f4ed PM |
2193 | case 597: /* lswi */ |
2194 | if (rb == 0) | |
2195 | rb = 32; /* # bytes to load */ | |
2196 | op->type = MKOP(LOAD_MULTI, 0, rb); | |
d120cdbc | 2197 | op->ea = ra ? regs->gpr[ra] : 0; |
c9f6f4ed PM |
2198 | break; |
2199 | ||
b69a1da9 | 2200 | #ifdef CONFIG_PPC_FPU |
0016a4cf PM |
2201 | case 535: /* lfsx */ |
2202 | case 567: /* lfsux */ | |
d2b65ac6 | 2203 | op->type = MKOP(LOAD_FP, u | FPCONV, 4); |
be96f633 | 2204 | break; |
0016a4cf PM |
2205 | |
2206 | case 599: /* lfdx */ | |
2207 | case 631: /* lfdux */ | |
be96f633 PM |
2208 | op->type = MKOP(LOAD_FP, u, 8); |
2209 | break; | |
0016a4cf PM |
2210 | |
2211 | case 663: /* stfsx */ | |
2212 | case 695: /* stfsux */ | |
d2b65ac6 | 2213 | op->type = MKOP(STORE_FP, u | FPCONV, 4); |
be96f633 | 2214 | break; |
0016a4cf PM |
2215 | |
2216 | case 727: /* stfdx */ | |
2217 | case 759: /* stfdux */ | |
be96f633 PM |
2218 | op->type = MKOP(STORE_FP, u, 8); |
2219 | break; | |
1f41fb79 PM |
2220 | |
2221 | #ifdef __powerpc64__ | |
2222 | case 791: /* lfdpx */ | |
2223 | op->type = MKOP(LOAD_FP, 0, 16); | |
2224 | break; | |
2225 | ||
d2b65ac6 PM |
2226 | case 855: /* lfiwax */ |
2227 | op->type = MKOP(LOAD_FP, SIGNEXT, 4); | |
2228 | break; | |
2229 | ||
2230 | case 887: /* lfiwzx */ | |
2231 | op->type = MKOP(LOAD_FP, 0, 4); | |
2232 | break; | |
2233 | ||
1f41fb79 PM |
2234 | case 919: /* stfdpx */ |
2235 | op->type = MKOP(STORE_FP, 0, 16); | |
2236 | break; | |
d2b65ac6 PM |
2237 | |
2238 | case 983: /* stfiwx */ | |
2239 | op->type = MKOP(STORE_FP, 0, 4); | |
2240 | break; | |
1f41fb79 PM |
2241 | #endif /* __powerpc64 */ |
2242 | #endif /* CONFIG_PPC_FPU */ | |
0016a4cf PM |
2243 | |
2244 | #ifdef __powerpc64__ | |
2245 | case 660: /* stdbrx */ | |
be96f633 PM |
2246 | op->type = MKOP(STORE, BYTEREV, 8); |
2247 | op->val = byterev_8(regs->gpr[rd]); | |
2248 | break; | |
0016a4cf PM |
2249 | |
2250 | #endif | |
c9f6f4ed PM |
2251 | case 661: /* stswx */ |
2252 | op->type = MKOP(STORE_MULTI, 0, regs->xer & 0x7f); | |
2253 | break; | |
2254 | ||
0016a4cf | 2255 | case 662: /* stwbrx */ |
be96f633 PM |
2256 | op->type = MKOP(STORE, BYTEREV, 4); |
2257 | op->val = byterev_4(regs->gpr[rd]); | |
2258 | break; | |
0016a4cf | 2259 | |
1f41fb79 | 2260 | case 725: /* stswi */ |
c9f6f4ed PM |
2261 | if (rb == 0) |
2262 | rb = 32; /* # bytes to store */ | |
2263 | op->type = MKOP(STORE_MULTI, 0, rb); | |
d120cdbc | 2264 | op->ea = ra ? regs->gpr[ra] : 0; |
c9f6f4ed PM |
2265 | break; |
2266 | ||
0016a4cf | 2267 | case 790: /* lhbrx */ |
be96f633 PM |
2268 | op->type = MKOP(LOAD, BYTEREV, 2); |
2269 | break; | |
0016a4cf PM |
2270 | |
2271 | case 918: /* sthbrx */ | |
be96f633 PM |
2272 | op->type = MKOP(STORE, BYTEREV, 2); |
2273 | op->val = byterev_2(regs->gpr[rd]); | |
2274 | break; | |
0016a4cf PM |
2275 | |
2276 | #ifdef CONFIG_VSX | |
350779a2 PM |
2277 | case 12: /* lxsiwzx */ |
2278 | op->reg = rd | ((instr & 1) << 5); | |
2279 | op->type = MKOP(LOAD_VSX, 0, 4); | |
2280 | op->element_size = 8; | |
2281 | break; | |
2282 | ||
2283 | case 76: /* lxsiwax */ | |
2284 | op->reg = rd | ((instr & 1) << 5); | |
2285 | op->type = MKOP(LOAD_VSX, SIGNEXT, 4); | |
2286 | op->element_size = 8; | |
2287 | break; | |
2288 | ||
2289 | case 140: /* stxsiwx */ | |
2290 | op->reg = rd | ((instr & 1) << 5); | |
2291 | op->type = MKOP(STORE_VSX, 0, 4); | |
2292 | op->element_size = 8; | |
2293 | break; | |
2294 | ||
2295 | case 268: /* lxvx */ | |
2296 | op->reg = rd | ((instr & 1) << 5); | |
2297 | op->type = MKOP(LOAD_VSX, 0, 16); | |
2298 | op->element_size = 16; | |
2299 | op->vsx_flags = VSX_CHECK_VEC; | |
2300 | break; | |
2301 | ||
2302 | case 269: /* lxvl */ | |
2303 | case 301: { /* lxvll */ | |
2304 | int nb; | |
2305 | op->reg = rd | ((instr & 1) << 5); | |
2306 | op->ea = ra ? regs->gpr[ra] : 0; | |
2307 | nb = regs->gpr[rb] & 0xff; | |
2308 | if (nb > 16) | |
2309 | nb = 16; | |
2310 | op->type = MKOP(LOAD_VSX, 0, nb); | |
2311 | op->element_size = 16; | |
2312 | op->vsx_flags = ((instr & 0x20) ? VSX_LDLEFT : 0) | | |
2313 | VSX_CHECK_VEC; | |
2314 | break; | |
2315 | } | |
2316 | case 332: /* lxvdsx */ | |
2317 | op->reg = rd | ((instr & 1) << 5); | |
2318 | op->type = MKOP(LOAD_VSX, 0, 8); | |
2319 | op->element_size = 8; | |
2320 | op->vsx_flags = VSX_SPLAT; | |
2321 | break; | |
2322 | ||
2323 | case 364: /* lxvwsx */ | |
2324 | op->reg = rd | ((instr & 1) << 5); | |
2325 | op->type = MKOP(LOAD_VSX, 0, 4); | |
2326 | op->element_size = 4; | |
2327 | op->vsx_flags = VSX_SPLAT | VSX_CHECK_VEC; | |
2328 | break; | |
2329 | ||
2330 | case 396: /* stxvx */ | |
2331 | op->reg = rd | ((instr & 1) << 5); | |
2332 | op->type = MKOP(STORE_VSX, 0, 16); | |
2333 | op->element_size = 16; | |
2334 | op->vsx_flags = VSX_CHECK_VEC; | |
2335 | break; | |
2336 | ||
2337 | case 397: /* stxvl */ | |
2338 | case 429: { /* stxvll */ | |
2339 | int nb; | |
2340 | op->reg = rd | ((instr & 1) << 5); | |
2341 | op->ea = ra ? regs->gpr[ra] : 0; | |
2342 | nb = regs->gpr[rb] & 0xff; | |
2343 | if (nb > 16) | |
2344 | nb = 16; | |
2345 | op->type = MKOP(STORE_VSX, 0, nb); | |
2346 | op->element_size = 16; | |
2347 | op->vsx_flags = ((instr & 0x20) ? VSX_LDLEFT : 0) | | |
2348 | VSX_CHECK_VEC; | |
2349 | break; | |
2350 | } | |
2351 | case 524: /* lxsspx */ | |
2352 | op->reg = rd | ((instr & 1) << 5); | |
2353 | op->type = MKOP(LOAD_VSX, 0, 4); | |
2354 | op->element_size = 8; | |
2355 | op->vsx_flags = VSX_FPCONV; | |
2356 | break; | |
2357 | ||
2358 | case 588: /* lxsdx */ | |
2359 | op->reg = rd | ((instr & 1) << 5); | |
2360 | op->type = MKOP(LOAD_VSX, 0, 8); | |
2361 | op->element_size = 8; | |
2362 | break; | |
2363 | ||
2364 | case 652: /* stxsspx */ | |
2365 | op->reg = rd | ((instr & 1) << 5); | |
2366 | op->type = MKOP(STORE_VSX, 0, 4); | |
2367 | op->element_size = 8; | |
2368 | op->vsx_flags = VSX_FPCONV; | |
2369 | break; | |
2370 | ||
2371 | case 716: /* stxsdx */ | |
2372 | op->reg = rd | ((instr & 1) << 5); | |
2373 | op->type = MKOP(STORE_VSX, 0, 8); | |
2374 | op->element_size = 8; | |
2375 | break; | |
2376 | ||
2377 | case 780: /* lxvw4x */ | |
2378 | op->reg = rd | ((instr & 1) << 5); | |
2379 | op->type = MKOP(LOAD_VSX, 0, 16); | |
2380 | op->element_size = 4; | |
2381 | break; | |
2382 | ||
2383 | case 781: /* lxsibzx */ | |
2384 | op->reg = rd | ((instr & 1) << 5); | |
2385 | op->type = MKOP(LOAD_VSX, 0, 1); | |
2386 | op->element_size = 8; | |
2387 | op->vsx_flags = VSX_CHECK_VEC; | |
2388 | break; | |
2389 | ||
2390 | case 812: /* lxvh8x */ | |
2391 | op->reg = rd | ((instr & 1) << 5); | |
2392 | op->type = MKOP(LOAD_VSX, 0, 16); | |
2393 | op->element_size = 2; | |
2394 | op->vsx_flags = VSX_CHECK_VEC; | |
2395 | break; | |
2396 | ||
2397 | case 813: /* lxsihzx */ | |
2398 | op->reg = rd | ((instr & 1) << 5); | |
2399 | op->type = MKOP(LOAD_VSX, 0, 2); | |
2400 | op->element_size = 8; | |
2401 | op->vsx_flags = VSX_CHECK_VEC; | |
2402 | break; | |
2403 | ||
0016a4cf | 2404 | case 844: /* lxvd2x */ |
be96f633 | 2405 | op->reg = rd | ((instr & 1) << 5); |
350779a2 PM |
2406 | op->type = MKOP(LOAD_VSX, 0, 16); |
2407 | op->element_size = 8; | |
2408 | break; | |
2409 | ||
2410 | case 876: /* lxvb16x */ | |
2411 | op->reg = rd | ((instr & 1) << 5); | |
2412 | op->type = MKOP(LOAD_VSX, 0, 16); | |
2413 | op->element_size = 1; | |
2414 | op->vsx_flags = VSX_CHECK_VEC; | |
2415 | break; | |
2416 | ||
2417 | case 908: /* stxvw4x */ | |
2418 | op->reg = rd | ((instr & 1) << 5); | |
2419 | op->type = MKOP(STORE_VSX, 0, 16); | |
2420 | op->element_size = 4; | |
2421 | break; | |
2422 | ||
2423 | case 909: /* stxsibx */ | |
2424 | op->reg = rd | ((instr & 1) << 5); | |
2425 | op->type = MKOP(STORE_VSX, 0, 1); | |
2426 | op->element_size = 8; | |
2427 | op->vsx_flags = VSX_CHECK_VEC; | |
2428 | break; | |
2429 | ||
2430 | case 940: /* stxvh8x */ | |
2431 | op->reg = rd | ((instr & 1) << 5); | |
2432 | op->type = MKOP(STORE_VSX, 0, 16); | |
2433 | op->element_size = 2; | |
2434 | op->vsx_flags = VSX_CHECK_VEC; | |
2435 | break; | |
2436 | ||
2437 | case 941: /* stxsihx */ | |
2438 | op->reg = rd | ((instr & 1) << 5); | |
2439 | op->type = MKOP(STORE_VSX, 0, 2); | |
2440 | op->element_size = 8; | |
2441 | op->vsx_flags = VSX_CHECK_VEC; | |
be96f633 | 2442 | break; |
0016a4cf PM |
2443 | |
2444 | case 972: /* stxvd2x */ | |
be96f633 | 2445 | op->reg = rd | ((instr & 1) << 5); |
350779a2 PM |
2446 | op->type = MKOP(STORE_VSX, 0, 16); |
2447 | op->element_size = 8; | |
2448 | break; | |
2449 | ||
2450 | case 1004: /* stxvb16x */ | |
2451 | op->reg = rd | ((instr & 1) << 5); | |
2452 | op->type = MKOP(STORE_VSX, 0, 16); | |
2453 | op->element_size = 1; | |
2454 | op->vsx_flags = VSX_CHECK_VEC; | |
be96f633 | 2455 | break; |
0016a4cf PM |
2456 | |
2457 | #endif /* CONFIG_VSX */ | |
2458 | } | |
2459 | break; | |
2460 | ||
2461 | case 32: /* lwz */ | |
2462 | case 33: /* lwzu */ | |
be96f633 PM |
2463 | op->type = MKOP(LOAD, u, 4); |
2464 | op->ea = dform_ea(instr, regs); | |
2465 | break; | |
0016a4cf PM |
2466 | |
2467 | case 34: /* lbz */ | |
2468 | case 35: /* lbzu */ | |
be96f633 PM |
2469 | op->type = MKOP(LOAD, u, 1); |
2470 | op->ea = dform_ea(instr, regs); | |
2471 | break; | |
0016a4cf PM |
2472 | |
2473 | case 36: /* stw */ | |
8e9f6937 | 2474 | case 37: /* stwu */ |
be96f633 PM |
2475 | op->type = MKOP(STORE, u, 4); |
2476 | op->ea = dform_ea(instr, regs); | |
2477 | break; | |
8e9f6937 | 2478 | |
0016a4cf PM |
2479 | case 38: /* stb */ |
2480 | case 39: /* stbu */ | |
be96f633 PM |
2481 | op->type = MKOP(STORE, u, 1); |
2482 | op->ea = dform_ea(instr, regs); | |
2483 | break; | |
0016a4cf PM |
2484 | |
2485 | case 40: /* lhz */ | |
2486 | case 41: /* lhzu */ | |
be96f633 PM |
2487 | op->type = MKOP(LOAD, u, 2); |
2488 | op->ea = dform_ea(instr, regs); | |
2489 | break; | |
0016a4cf PM |
2490 | |
2491 | case 42: /* lha */ | |
2492 | case 43: /* lhau */ | |
be96f633 PM |
2493 | op->type = MKOP(LOAD, SIGNEXT | u, 2); |
2494 | op->ea = dform_ea(instr, regs); | |
2495 | break; | |
0016a4cf PM |
2496 | |
2497 | case 44: /* sth */ | |
2498 | case 45: /* sthu */ | |
be96f633 PM |
2499 | op->type = MKOP(STORE, u, 2); |
2500 | op->ea = dform_ea(instr, regs); | |
2501 | break; | |
0016a4cf PM |
2502 | |
2503 | case 46: /* lmw */ | |
0016a4cf PM |
2504 | if (ra >= rd) |
2505 | break; /* invalid form, ra in range to load */ | |
c9f6f4ed | 2506 | op->type = MKOP(LOAD_MULTI, 0, 4 * (32 - rd)); |
be96f633 PM |
2507 | op->ea = dform_ea(instr, regs); |
2508 | break; | |
0016a4cf PM |
2509 | |
2510 | case 47: /* stmw */ | |
c9f6f4ed | 2511 | op->type = MKOP(STORE_MULTI, 0, 4 * (32 - rd)); |
be96f633 PM |
2512 | op->ea = dform_ea(instr, regs); |
2513 | break; | |
0016a4cf | 2514 | |
cd64d169 | 2515 | #ifdef CONFIG_PPC_FPU |
0016a4cf PM |
2516 | case 48: /* lfs */ |
2517 | case 49: /* lfsu */ | |
d2b65ac6 | 2518 | op->type = MKOP(LOAD_FP, u | FPCONV, 4); |
be96f633 PM |
2519 | op->ea = dform_ea(instr, regs); |
2520 | break; | |
0016a4cf PM |
2521 | |
2522 | case 50: /* lfd */ | |
2523 | case 51: /* lfdu */ | |
be96f633 PM |
2524 | op->type = MKOP(LOAD_FP, u, 8); |
2525 | op->ea = dform_ea(instr, regs); | |
2526 | break; | |
0016a4cf PM |
2527 | |
2528 | case 52: /* stfs */ | |
2529 | case 53: /* stfsu */ | |
d2b65ac6 | 2530 | op->type = MKOP(STORE_FP, u | FPCONV, 4); |
be96f633 PM |
2531 | op->ea = dform_ea(instr, regs); |
2532 | break; | |
0016a4cf PM |
2533 | |
2534 | case 54: /* stfd */ | |
2535 | case 55: /* stfdu */ | |
be96f633 PM |
2536 | op->type = MKOP(STORE_FP, u, 8); |
2537 | op->ea = dform_ea(instr, regs); | |
2538 | break; | |
cd64d169 | 2539 | #endif |
0016a4cf | 2540 | |
350779a2 PM |
2541 | #ifdef __powerpc64__ |
2542 | case 56: /* lq */ | |
2543 | if (!((rd & 1) || (rd == ra))) | |
2544 | op->type = MKOP(LOAD, 0, 16); | |
2545 | op->ea = dqform_ea(instr, regs); | |
2546 | break; | |
2547 | #endif | |
2548 | ||
2549 | #ifdef CONFIG_VSX | |
1f41fb79 | 2550 | case 57: /* lfdp, lxsd, lxssp */ |
350779a2 PM |
2551 | op->ea = dsform_ea(instr, regs); |
2552 | switch (instr & 3) { | |
1f41fb79 PM |
2553 | case 0: /* lfdp */ |
2554 | if (rd & 1) | |
2555 | break; /* reg must be even */ | |
2556 | op->type = MKOP(LOAD_FP, 0, 16); | |
2557 | break; | |
350779a2 PM |
2558 | case 2: /* lxsd */ |
2559 | op->reg = rd + 32; | |
2560 | op->type = MKOP(LOAD_VSX, 0, 8); | |
2561 | op->element_size = 8; | |
2562 | op->vsx_flags = VSX_CHECK_VEC; | |
2563 | break; | |
2564 | case 3: /* lxssp */ | |
2565 | op->reg = rd + 32; | |
2566 | op->type = MKOP(LOAD_VSX, 0, 4); | |
2567 | op->element_size = 8; | |
2568 | op->vsx_flags = VSX_FPCONV | VSX_CHECK_VEC; | |
2569 | break; | |
2570 | } | |
2571 | break; | |
2572 | #endif /* CONFIG_VSX */ | |
2573 | ||
0016a4cf PM |
2574 | #ifdef __powerpc64__ |
2575 | case 58: /* ld[u], lwa */ | |
be96f633 | 2576 | op->ea = dsform_ea(instr, regs); |
0016a4cf PM |
2577 | switch (instr & 3) { |
2578 | case 0: /* ld */ | |
be96f633 PM |
2579 | op->type = MKOP(LOAD, 0, 8); |
2580 | break; | |
0016a4cf | 2581 | case 1: /* ldu */ |
be96f633 PM |
2582 | op->type = MKOP(LOAD, UPDATE, 8); |
2583 | break; | |
0016a4cf | 2584 | case 2: /* lwa */ |
be96f633 PM |
2585 | op->type = MKOP(LOAD, SIGNEXT, 4); |
2586 | break; | |
0016a4cf PM |
2587 | } |
2588 | break; | |
350779a2 PM |
2589 | #endif |
2590 | ||
2591 | #ifdef CONFIG_VSX | |
1f41fb79 | 2592 | case 61: /* stfdp, lxv, stxsd, stxssp, stxv */ |
350779a2 | 2593 | switch (instr & 7) { |
1f41fb79 PM |
2594 | case 0: /* stfdp with LSB of DS field = 0 */ |
2595 | case 4: /* stfdp with LSB of DS field = 1 */ | |
2596 | op->ea = dsform_ea(instr, regs); | |
2597 | op->type = MKOP(STORE_FP, 0, 16); | |
2598 | break; | |
2599 | ||
350779a2 PM |
2600 | case 1: /* lxv */ |
2601 | op->ea = dqform_ea(instr, regs); | |
2602 | if (instr & 8) | |
2603 | op->reg = rd + 32; | |
2604 | op->type = MKOP(LOAD_VSX, 0, 16); | |
2605 | op->element_size = 16; | |
2606 | op->vsx_flags = VSX_CHECK_VEC; | |
2607 | break; | |
2608 | ||
2609 | case 2: /* stxsd with LSB of DS field = 0 */ | |
2610 | case 6: /* stxsd with LSB of DS field = 1 */ | |
2611 | op->ea = dsform_ea(instr, regs); | |
2612 | op->reg = rd + 32; | |
2613 | op->type = MKOP(STORE_VSX, 0, 8); | |
2614 | op->element_size = 8; | |
2615 | op->vsx_flags = VSX_CHECK_VEC; | |
2616 | break; | |
2617 | ||
2618 | case 3: /* stxssp with LSB of DS field = 0 */ | |
2619 | case 7: /* stxssp with LSB of DS field = 1 */ | |
2620 | op->ea = dsform_ea(instr, regs); | |
2621 | op->reg = rd + 32; | |
2622 | op->type = MKOP(STORE_VSX, 0, 4); | |
2623 | op->element_size = 8; | |
2624 | op->vsx_flags = VSX_FPCONV | VSX_CHECK_VEC; | |
2625 | break; | |
2626 | ||
2627 | case 5: /* stxv */ | |
2628 | op->ea = dqform_ea(instr, regs); | |
2629 | if (instr & 8) | |
2630 | op->reg = rd + 32; | |
2631 | op->type = MKOP(STORE_VSX, 0, 16); | |
2632 | op->element_size = 16; | |
2633 | op->vsx_flags = VSX_CHECK_VEC; | |
2634 | break; | |
2635 | } | |
2636 | break; | |
2637 | #endif /* CONFIG_VSX */ | |
0016a4cf | 2638 | |
350779a2 | 2639 | #ifdef __powerpc64__ |
0016a4cf | 2640 | case 62: /* std[u] */ |
be96f633 | 2641 | op->ea = dsform_ea(instr, regs); |
0016a4cf PM |
2642 | switch (instr & 3) { |
2643 | case 0: /* std */ | |
be96f633 PM |
2644 | op->type = MKOP(STORE, 0, 8); |
2645 | break; | |
0016a4cf | 2646 | case 1: /* stdu */ |
be96f633 PM |
2647 | op->type = MKOP(STORE, UPDATE, 8); |
2648 | break; | |
350779a2 PM |
2649 | case 2: /* stq */ |
2650 | if (!(rd & 1)) | |
2651 | op->type = MKOP(STORE, 0, 16); | |
2652 | break; | |
0016a4cf PM |
2653 | } |
2654 | break; | |
2655 | #endif /* __powerpc64__ */ | |
2656 | ||
2657 | } | |
83afab4c RB |
2658 | |
2659 | #ifdef CONFIG_VSX | |
2660 | if ((GETTYPE(op->type) == LOAD_VSX || | |
2661 | GETTYPE(op->type) == STORE_VSX) && | |
2662 | !cpu_has_feature(CPU_FTR_VSX)) { | |
2663 | return -1; | |
2664 | } | |
2665 | #endif /* CONFIG_VSX */ | |
2666 | ||
be96f633 | 2667 | return 0; |
0016a4cf PM |
2668 | |
2669 | logical_done: | |
2670 | if (instr & 1) | |
ad47ff3e | 2671 | set_cr0(regs, op); |
3cdfcbfd PM |
2672 | logical_done_nocc: |
2673 | op->reg = ra; | |
2674 | op->type |= SETREG; | |
2675 | return 1; | |
0016a4cf PM |
2676 | |
2677 | arith_done: | |
2678 | if (instr & 1) | |
ad47ff3e | 2679 | set_cr0(regs, op); |
3cdfcbfd PM |
2680 | compute_done: |
2681 | op->reg = rd; | |
2682 | op->type |= SETREG; | |
be96f633 PM |
2683 | return 1; |
2684 | ||
2685 | priv: | |
2686 | op->type = INTERRUPT | 0x700; | |
2687 | op->val = SRR1_PROGPRIV; | |
2688 | return 0; | |
2689 | ||
cf87c3f6 PM |
2690 | trap: |
2691 | op->type = INTERRUPT | 0x700; | |
2692 | op->val = SRR1_PROGTRAP; | |
2693 | return 0; | |
be96f633 PM |
2694 | } |
2695 | EXPORT_SYMBOL_GPL(analyse_instr); | |
71f6e58e | 2696 | NOKPROBE_SYMBOL(analyse_instr); |
be96f633 PM |
2697 | |
2698 | /* | |
2699 | * For PPC32 we always use stwu with r1 to change the stack pointer. | |
2700 | * So this emulated store may corrupt the exception frame, now we | |
2701 | * have to provide the exception frame trampoline, which is pushed | |
2702 | * below the kprobed function stack. So we only update gpr[1] but | |
2703 | * don't emulate the real store operation. We will do real store | |
2704 | * operation safely in exception return code by checking this flag. | |
2705 | */ | |
71f6e58e | 2706 | static nokprobe_inline int handle_stack_update(unsigned long ea, struct pt_regs *regs) |
be96f633 PM |
2707 | { |
2708 | #ifdef CONFIG_PPC32 | |
2709 | /* | |
2710 | * Check if we will touch kernel stack overflow | |
2711 | */ | |
2712 | if (ea - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) { | |
2713 | printk(KERN_CRIT "Can't kprobe this since kernel stack would overflow.\n"); | |
2714 | return -EINVAL; | |
2715 | } | |
2716 | #endif /* CONFIG_PPC32 */ | |
2717 | /* | |
2718 | * Check if we already set since that means we'll | |
2719 | * lose the previous value. | |
2720 | */ | |
2721 | WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE)); | |
2722 | set_thread_flag(TIF_EMULATE_STACK_STORE); | |
2723 | return 0; | |
2724 | } | |
2725 | ||
71f6e58e | 2726 | static nokprobe_inline void do_signext(unsigned long *valp, int size) |
be96f633 PM |
2727 | { |
2728 | switch (size) { | |
2729 | case 2: | |
2730 | *valp = (signed short) *valp; | |
2731 | break; | |
2732 | case 4: | |
2733 | *valp = (signed int) *valp; | |
2734 | break; | |
2735 | } | |
2736 | } | |
2737 | ||
71f6e58e | 2738 | static nokprobe_inline void do_byterev(unsigned long *valp, int size) |
be96f633 PM |
2739 | { |
2740 | switch (size) { | |
2741 | case 2: | |
2742 | *valp = byterev_2(*valp); | |
2743 | break; | |
2744 | case 4: | |
2745 | *valp = byterev_4(*valp); | |
2746 | break; | |
2747 | #ifdef __powerpc64__ | |
2748 | case 8: | |
2749 | *valp = byterev_8(*valp); | |
2750 | break; | |
2751 | #endif | |
2752 | } | |
2753 | } | |
2754 | ||
3cdfcbfd PM |
2755 | /* |
2756 | * Emulate an instruction that can be executed just by updating | |
2757 | * fields in *regs. | |
2758 | */ | |
2759 | void emulate_update_regs(struct pt_regs *regs, struct instruction_op *op) | |
2760 | { | |
2761 | unsigned long next_pc; | |
2762 | ||
2763 | next_pc = truncate_if_32bit(regs->msr, regs->nip + 4); | |
e6684d07 | 2764 | switch (GETTYPE(op->type)) { |
3cdfcbfd PM |
2765 | case COMPUTE: |
2766 | if (op->type & SETREG) | |
2767 | regs->gpr[op->reg] = op->val; | |
2768 | if (op->type & SETCC) | |
2769 | regs->ccr = op->ccval; | |
2770 | if (op->type & SETXER) | |
2771 | regs->xer = op->xerval; | |
2772 | break; | |
2773 | ||
2774 | case BRANCH: | |
2775 | if (op->type & SETLK) | |
2776 | regs->link = next_pc; | |
2777 | if (op->type & BRTAKEN) | |
2778 | next_pc = op->val; | |
2779 | if (op->type & DECCTR) | |
2780 | --regs->ctr; | |
2781 | break; | |
2782 | ||
2783 | case BARRIER: | |
2784 | switch (op->type & BARRIER_MASK) { | |
2785 | case BARRIER_SYNC: | |
2786 | mb(); | |
2787 | break; | |
2788 | case BARRIER_ISYNC: | |
2789 | isync(); | |
2790 | break; | |
2791 | case BARRIER_EIEIO: | |
2792 | eieio(); | |
2793 | break; | |
2794 | case BARRIER_LWSYNC: | |
2795 | asm volatile("lwsync" : : : "memory"); | |
2796 | break; | |
2797 | case BARRIER_PTESYNC: | |
2798 | asm volatile("ptesync" : : : "memory"); | |
2799 | break; | |
2800 | } | |
2801 | break; | |
2802 | ||
2803 | case MFSPR: | |
2804 | switch (op->spr) { | |
2805 | case SPRN_XER: | |
2806 | regs->gpr[op->reg] = regs->xer & 0xffffffffUL; | |
2807 | break; | |
2808 | case SPRN_LR: | |
2809 | regs->gpr[op->reg] = regs->link; | |
2810 | break; | |
2811 | case SPRN_CTR: | |
2812 | regs->gpr[op->reg] = regs->ctr; | |
2813 | break; | |
2814 | default: | |
2815 | WARN_ON_ONCE(1); | |
2816 | } | |
2817 | break; | |
2818 | ||
2819 | case MTSPR: | |
2820 | switch (op->spr) { | |
2821 | case SPRN_XER: | |
2822 | regs->xer = op->val & 0xffffffffUL; | |
2823 | break; | |
2824 | case SPRN_LR: | |
2825 | regs->link = op->val; | |
2826 | break; | |
2827 | case SPRN_CTR: | |
2828 | regs->ctr = op->val; | |
2829 | break; | |
2830 | default: | |
2831 | WARN_ON_ONCE(1); | |
2832 | } | |
2833 | break; | |
2834 | ||
2835 | default: | |
2836 | WARN_ON_ONCE(1); | |
2837 | } | |
2838 | regs->nip = next_pc; | |
2839 | } | |
67ac0bfe | 2840 | NOKPROBE_SYMBOL(emulate_update_regs); |
3cdfcbfd | 2841 | |
be96f633 | 2842 | /* |
a53d5182 PM |
2843 | * Emulate a previously-analysed load or store instruction. |
2844 | * Return values are: | |
2845 | * 0 = instruction emulated successfully | |
2846 | * -EFAULT = address out of range or access faulted (regs->dar | |
2847 | * contains the faulting address) | |
2848 | * -EACCES = misaligned access, instruction requires alignment | |
2849 | * -EINVAL = unknown operation in *op | |
be96f633 | 2850 | */ |
a53d5182 | 2851 | int emulate_loadstore(struct pt_regs *regs, struct instruction_op *op) |
be96f633 | 2852 | { |
a53d5182 | 2853 | int err, size, type; |
c9f6f4ed | 2854 | int i, rd, nb; |
a53d5182 PM |
2855 | unsigned int cr; |
2856 | unsigned long val; | |
d120cdbc | 2857 | unsigned long ea; |
d955189a | 2858 | bool cross_endian; |
be96f633 | 2859 | |
be96f633 | 2860 | err = 0; |
a53d5182 | 2861 | size = GETSIZE(op->type); |
e6684d07 | 2862 | type = GETTYPE(op->type); |
d955189a | 2863 | cross_endian = (regs->msr & MSR_LE) != (MSR_KERNEL & MSR_LE); |
a53d5182 | 2864 | ea = truncate_if_32bit(regs->msr, op->ea); |
d120cdbc PM |
2865 | |
2866 | switch (type) { | |
be96f633 | 2867 | case LARX: |
d120cdbc | 2868 | if (ea & (size - 1)) |
a53d5182 | 2869 | return -EACCES; /* can't handle misaligned */ |
d120cdbc | 2870 | if (!address_ok(regs, ea, size)) |
a53d5182 | 2871 | return -EFAULT; |
be96f633 | 2872 | err = 0; |
3b79b261 | 2873 | val = 0; |
be96f633 | 2874 | switch (size) { |
350779a2 PM |
2875 | #ifdef __powerpc64__ |
2876 | case 1: | |
d120cdbc | 2877 | __get_user_asmx(val, ea, err, "lbarx"); |
350779a2 PM |
2878 | break; |
2879 | case 2: | |
d120cdbc | 2880 | __get_user_asmx(val, ea, err, "lharx"); |
350779a2 PM |
2881 | break; |
2882 | #endif | |
be96f633 | 2883 | case 4: |
d120cdbc | 2884 | __get_user_asmx(val, ea, err, "lwarx"); |
be96f633 | 2885 | break; |
dd217310 | 2886 | #ifdef __powerpc64__ |
be96f633 | 2887 | case 8: |
d120cdbc | 2888 | __get_user_asmx(val, ea, err, "ldarx"); |
be96f633 | 2889 | break; |
350779a2 | 2890 | case 16: |
a53d5182 | 2891 | err = do_lqarx(ea, ®s->gpr[op->reg]); |
b9da9c8a | 2892 | break; |
dd217310 | 2893 | #endif |
be96f633 | 2894 | default: |
a53d5182 | 2895 | return -EINVAL; |
be96f633 | 2896 | } |
b9da9c8a PM |
2897 | if (err) { |
2898 | regs->dar = ea; | |
a53d5182 | 2899 | break; |
b9da9c8a PM |
2900 | } |
2901 | if (size < 16) | |
a53d5182 PM |
2902 | regs->gpr[op->reg] = val; |
2903 | break; | |
be96f633 PM |
2904 | |
2905 | case STCX: | |
d120cdbc | 2906 | if (ea & (size - 1)) |
a53d5182 | 2907 | return -EACCES; /* can't handle misaligned */ |
d120cdbc | 2908 | if (!address_ok(regs, ea, size)) |
a53d5182 | 2909 | return -EFAULT; |
be96f633 PM |
2910 | err = 0; |
2911 | switch (size) { | |
350779a2 PM |
2912 | #ifdef __powerpc64__ |
2913 | case 1: | |
a53d5182 | 2914 | __put_user_asmx(op->val, ea, err, "stbcx.", cr); |
350779a2 PM |
2915 | break; |
2916 | case 2: | |
a53d5182 | 2917 | __put_user_asmx(op->val, ea, err, "stbcx.", cr); |
350779a2 PM |
2918 | break; |
2919 | #endif | |
be96f633 | 2920 | case 4: |
a53d5182 | 2921 | __put_user_asmx(op->val, ea, err, "stwcx.", cr); |
be96f633 | 2922 | break; |
dd217310 | 2923 | #ifdef __powerpc64__ |
be96f633 | 2924 | case 8: |
a53d5182 | 2925 | __put_user_asmx(op->val, ea, err, "stdcx.", cr); |
be96f633 | 2926 | break; |
350779a2 | 2927 | case 16: |
a53d5182 PM |
2928 | err = do_stqcx(ea, regs->gpr[op->reg], |
2929 | regs->gpr[op->reg + 1], &cr); | |
350779a2 | 2930 | break; |
dd217310 | 2931 | #endif |
be96f633 | 2932 | default: |
a53d5182 | 2933 | return -EINVAL; |
be96f633 PM |
2934 | } |
2935 | if (!err) | |
2936 | regs->ccr = (regs->ccr & 0x0fffffff) | | |
2937 | (cr & 0xe0000000) | | |
2938 | ((regs->xer >> 3) & 0x10000000); | |
b9da9c8a PM |
2939 | else |
2940 | regs->dar = ea; | |
a53d5182 | 2941 | break; |
be96f633 PM |
2942 | |
2943 | case LOAD: | |
350779a2 PM |
2944 | #ifdef __powerpc64__ |
2945 | if (size == 16) { | |
a53d5182 PM |
2946 | err = emulate_lq(regs, ea, op->reg, cross_endian); |
2947 | break; | |
350779a2 PM |
2948 | } |
2949 | #endif | |
a53d5182 | 2950 | err = read_mem(®s->gpr[op->reg], ea, size, regs); |
be96f633 | 2951 | if (!err) { |
a53d5182 PM |
2952 | if (op->type & SIGNEXT) |
2953 | do_signext(®s->gpr[op->reg], size); | |
2954 | if ((op->type & BYTEREV) == (cross_endian ? 0 : BYTEREV)) | |
2955 | do_byterev(®s->gpr[op->reg], size); | |
be96f633 | 2956 | } |
a53d5182 | 2957 | break; |
be96f633 | 2958 | |
7048c846 | 2959 | #ifdef CONFIG_PPC_FPU |
be96f633 | 2960 | case LOAD_FP: |
c22435a5 PM |
2961 | /* |
2962 | * If the instruction is in userspace, we can emulate it even | |
2963 | * if the VMX state is not live, because we have the state | |
2964 | * stored in the thread_struct. If the instruction is in | |
2965 | * the kernel, we must not touch the state in the thread_struct. | |
2966 | */ | |
2967 | if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_FP)) | |
ee0a54d7 | 2968 | return 0; |
d2b65ac6 | 2969 | err = do_fp_load(op, ea, regs, cross_endian); |
a53d5182 | 2970 | break; |
7048c846 | 2971 | #endif |
be96f633 PM |
2972 | #ifdef CONFIG_ALTIVEC |
2973 | case LOAD_VMX: | |
c22435a5 | 2974 | if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_VEC)) |
ee0a54d7 | 2975 | return 0; |
a53d5182 PM |
2976 | err = do_vec_load(op->reg, ea, size, regs, cross_endian); |
2977 | break; | |
be96f633 PM |
2978 | #endif |
2979 | #ifdef CONFIG_VSX | |
350779a2 | 2980 | case LOAD_VSX: { |
350779a2 PM |
2981 | unsigned long msrbit = MSR_VSX; |
2982 | ||
2983 | /* | |
2984 | * Some VSX instructions check the MSR_VEC bit rather than MSR_VSX | |
2985 | * when the target of the instruction is a vector register. | |
2986 | */ | |
a53d5182 | 2987 | if (op->reg >= 32 && (op->vsx_flags & VSX_CHECK_VEC)) |
350779a2 | 2988 | msrbit = MSR_VEC; |
c22435a5 | 2989 | if (!(regs->msr & MSR_PR) && !(regs->msr & msrbit)) |
ee0a54d7 | 2990 | return 0; |
a53d5182 PM |
2991 | err = do_vsx_load(op, ea, regs, cross_endian); |
2992 | break; | |
350779a2 | 2993 | } |
be96f633 PM |
2994 | #endif |
2995 | case LOAD_MULTI: | |
d955189a PM |
2996 | if (!address_ok(regs, ea, size)) |
2997 | return -EFAULT; | |
a53d5182 | 2998 | rd = op->reg; |
c9f6f4ed | 2999 | for (i = 0; i < size; i += 4) { |
d955189a PM |
3000 | unsigned int v32 = 0; |
3001 | ||
c9f6f4ed PM |
3002 | nb = size - i; |
3003 | if (nb > 4) | |
3004 | nb = 4; | |
d955189a | 3005 | err = copy_mem_in((u8 *) &v32, ea, nb, regs); |
be96f633 | 3006 | if (err) |
a53d5182 | 3007 | break; |
d955189a PM |
3008 | if (unlikely(cross_endian)) |
3009 | v32 = byterev_4(v32); | |
3010 | regs->gpr[rd] = v32; | |
d120cdbc | 3011 | ea += 4; |
45f62159 PM |
3012 | /* reg number wraps from 31 to 0 for lsw[ix] */ |
3013 | rd = (rd + 1) & 0x1f; | |
c9f6f4ed | 3014 | } |
a53d5182 | 3015 | break; |
be96f633 PM |
3016 | |
3017 | case STORE: | |
350779a2 PM |
3018 | #ifdef __powerpc64__ |
3019 | if (size == 16) { | |
a53d5182 PM |
3020 | err = emulate_stq(regs, ea, op->reg, cross_endian); |
3021 | break; | |
350779a2 PM |
3022 | } |
3023 | #endif | |
a53d5182 PM |
3024 | if ((op->type & UPDATE) && size == sizeof(long) && |
3025 | op->reg == 1 && op->update_reg == 1 && | |
be96f633 | 3026 | !(regs->msr & MSR_PR) && |
d120cdbc PM |
3027 | ea >= regs->gpr[1] - STACK_INT_FRAME_SIZE) { |
3028 | err = handle_stack_update(ea, regs); | |
a53d5182 | 3029 | break; |
be96f633 | 3030 | } |
d955189a | 3031 | if (unlikely(cross_endian)) |
a53d5182 PM |
3032 | do_byterev(&op->val, size); |
3033 | err = write_mem(op->val, ea, size, regs); | |
3034 | break; | |
be96f633 | 3035 | |
7048c846 | 3036 | #ifdef CONFIG_PPC_FPU |
be96f633 | 3037 | case STORE_FP: |
c22435a5 | 3038 | if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_FP)) |
ee0a54d7 | 3039 | return 0; |
d2b65ac6 | 3040 | err = do_fp_store(op, ea, regs, cross_endian); |
a53d5182 | 3041 | break; |
7048c846 | 3042 | #endif |
be96f633 PM |
3043 | #ifdef CONFIG_ALTIVEC |
3044 | case STORE_VMX: | |
c22435a5 | 3045 | if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_VEC)) |
ee0a54d7 | 3046 | return 0; |
a53d5182 PM |
3047 | err = do_vec_store(op->reg, ea, size, regs, cross_endian); |
3048 | break; | |
be96f633 PM |
3049 | #endif |
3050 | #ifdef CONFIG_VSX | |
350779a2 | 3051 | case STORE_VSX: { |
350779a2 PM |
3052 | unsigned long msrbit = MSR_VSX; |
3053 | ||
3054 | /* | |
3055 | * Some VSX instructions check the MSR_VEC bit rather than MSR_VSX | |
3056 | * when the target of the instruction is a vector register. | |
3057 | */ | |
a53d5182 | 3058 | if (op->reg >= 32 && (op->vsx_flags & VSX_CHECK_VEC)) |
350779a2 | 3059 | msrbit = MSR_VEC; |
c22435a5 | 3060 | if (!(regs->msr & MSR_PR) && !(regs->msr & msrbit)) |
ee0a54d7 | 3061 | return 0; |
a53d5182 PM |
3062 | err = do_vsx_store(op, ea, regs, cross_endian); |
3063 | break; | |
350779a2 | 3064 | } |
be96f633 PM |
3065 | #endif |
3066 | case STORE_MULTI: | |
d955189a PM |
3067 | if (!address_ok(regs, ea, size)) |
3068 | return -EFAULT; | |
a53d5182 | 3069 | rd = op->reg; |
c9f6f4ed | 3070 | for (i = 0; i < size; i += 4) { |
d955189a PM |
3071 | unsigned int v32 = regs->gpr[rd]; |
3072 | ||
c9f6f4ed PM |
3073 | nb = size - i; |
3074 | if (nb > 4) | |
3075 | nb = 4; | |
d955189a PM |
3076 | if (unlikely(cross_endian)) |
3077 | v32 = byterev_4(v32); | |
3078 | err = copy_mem_out((u8 *) &v32, ea, nb, regs); | |
be96f633 | 3079 | if (err) |
a53d5182 | 3080 | break; |
d120cdbc | 3081 | ea += 4; |
45f62159 PM |
3082 | /* reg number wraps from 31 to 0 for stsw[ix] */ |
3083 | rd = (rd + 1) & 0x1f; | |
c9f6f4ed | 3084 | } |
a53d5182 PM |
3085 | break; |
3086 | ||
3087 | default: | |
3088 | return -EINVAL; | |
3089 | } | |
3090 | ||
3091 | if (err) | |
3092 | return err; | |
3093 | ||
3094 | if (op->type & UPDATE) | |
3095 | regs->gpr[op->update_reg] = op->ea; | |
3096 | ||
3097 | return 0; | |
3098 | } | |
3099 | NOKPROBE_SYMBOL(emulate_loadstore); | |
3100 | ||
3101 | /* | |
3102 | * Emulate instructions that cause a transfer of control, | |
3103 | * loads and stores, and a few other instructions. | |
3104 | * Returns 1 if the step was emulated, 0 if not, | |
3105 | * or -1 if the instruction is one that should not be stepped, | |
3106 | * such as an rfid, or a mtmsrd that would clear MSR_RI. | |
3107 | */ | |
3108 | int emulate_step(struct pt_regs *regs, unsigned int instr) | |
3109 | { | |
3110 | struct instruction_op op; | |
3111 | int r, err, type; | |
3112 | unsigned long val; | |
3113 | unsigned long ea; | |
3114 | ||
3115 | r = analyse_instr(&op, regs, instr); | |
3116 | if (r < 0) | |
3117 | return r; | |
3118 | if (r > 0) { | |
3119 | emulate_update_regs(regs, &op); | |
3120 | return 1; | |
3121 | } | |
3122 | ||
3123 | err = 0; | |
e6684d07 | 3124 | type = GETTYPE(op.type); |
a53d5182 PM |
3125 | |
3126 | if (OP_IS_LOAD_STORE(type)) { | |
3127 | err = emulate_loadstore(regs, &op); | |
3128 | if (err) | |
3129 | return 0; | |
3130 | goto instr_done; | |
3131 | } | |
3132 | ||
3133 | switch (type) { | |
3134 | case CACHEOP: | |
3135 | ea = truncate_if_32bit(regs->msr, op.ea); | |
3136 | if (!address_ok(regs, ea, 8)) | |
3137 | return 0; | |
3138 | switch (op.type & CACHEOP_MASK) { | |
3139 | case DCBST: | |
3140 | __cacheop_user_asmx(ea, err, "dcbst"); | |
3141 | break; | |
3142 | case DCBF: | |
3143 | __cacheop_user_asmx(ea, err, "dcbf"); | |
3144 | break; | |
3145 | case DCBTST: | |
3146 | if (op.reg == 0) | |
3147 | prefetchw((void *) ea); | |
3148 | break; | |
3149 | case DCBT: | |
3150 | if (op.reg == 0) | |
3151 | prefetch((void *) ea); | |
3152 | break; | |
3153 | case ICBI: | |
3154 | __cacheop_user_asmx(ea, err, "icbi"); | |
3155 | break; | |
3156 | case DCBZ: | |
3157 | err = emulate_dcbz(ea, regs); | |
3158 | break; | |
3159 | } | |
3160 | if (err) { | |
3161 | regs->dar = ea; | |
3162 | return 0; | |
3163 | } | |
be96f633 PM |
3164 | goto instr_done; |
3165 | ||
3166 | case MFMSR: | |
3167 | regs->gpr[op.reg] = regs->msr & MSR_MASK; | |
3168 | goto instr_done; | |
3169 | ||
3170 | case MTMSR: | |
3171 | val = regs->gpr[op.reg]; | |
3172 | if ((val & MSR_RI) == 0) | |
3173 | /* can't step mtmsr[d] that would clear MSR_RI */ | |
3174 | return -1; | |
3175 | /* here op.val is the mask of bits to change */ | |
3176 | regs->msr = (regs->msr & ~op.val) | (val & op.val); | |
3177 | goto instr_done; | |
3178 | ||
3179 | #ifdef CONFIG_PPC64 | |
3180 | case SYSCALL: /* sc */ | |
3181 | /* | |
3182 | * N.B. this uses knowledge about how the syscall | |
3183 | * entry code works. If that is changed, this will | |
3184 | * need to be changed also. | |
3185 | */ | |
3186 | if (regs->gpr[0] == 0x1ebe && | |
3187 | cpu_has_feature(CPU_FTR_REAL_LE)) { | |
3188 | regs->msr ^= MSR_LE; | |
3189 | goto instr_done; | |
3190 | } | |
3191 | regs->gpr[9] = regs->gpr[13]; | |
3192 | regs->gpr[10] = MSR_KERNEL; | |
3193 | regs->gpr[11] = regs->nip + 4; | |
3194 | regs->gpr[12] = regs->msr & MSR_MASK; | |
3195 | regs->gpr[13] = (unsigned long) get_paca(); | |
3196 | regs->nip = (unsigned long) &system_call_common; | |
3197 | regs->msr = MSR_KERNEL; | |
3198 | return 1; | |
3199 | ||
3200 | case RFI: | |
3201 | return -1; | |
3202 | #endif | |
3203 | } | |
3204 | return 0; | |
3205 | ||
be96f633 PM |
3206 | instr_done: |
3207 | regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4); | |
3208 | return 1; | |
14cf11af | 3209 | } |
71f6e58e | 3210 | NOKPROBE_SYMBOL(emulate_step); |