|  | /* | 
|  | * Single-step support. | 
|  | * | 
|  | * Copyright (C) 2004 Paul Mackerras <paulus@au.ibm.com>, IBM | 
|  | * | 
|  | * This program is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU General Public License | 
|  | * as published by the Free Software Foundation; either version | 
|  | * 2 of the License, or (at your option) any later version. | 
|  | */ | 
|  | #include <linux/kernel.h> | 
|  | #include <linux/kprobes.h> | 
|  | #include <linux/ptrace.h> | 
|  | #include <linux/prefetch.h> | 
|  | #include <asm/sstep.h> | 
|  | #include <asm/processor.h> | 
|  | #include <linux/uaccess.h> | 
|  | #include <asm/cpu_has_feature.h> | 
|  | #include <asm/cputable.h> | 
|  |  | 
|  | extern char system_call_common[]; | 
|  |  | 
|  | #ifdef CONFIG_PPC64 | 
|  | /* Bits in SRR1 that are copied from MSR */ | 
|  | #define MSR_MASK	0xffffffff87c0ffffUL | 
|  | #else | 
|  | #define MSR_MASK	0x87c0ffff | 
|  | #endif | 
|  |  | 
|  | /* Bits in XER */ | 
|  | #define XER_SO		0x80000000U | 
|  | #define XER_OV		0x40000000U | 
|  | #define XER_CA		0x20000000U | 
|  | #define XER_OV32	0x00080000U | 
|  | #define XER_CA32	0x00040000U | 
|  |  | 
|  | #ifdef CONFIG_PPC_FPU | 
|  | /* | 
|  | * Functions in ldstfp.S | 
|  | */ | 
|  | extern void get_fpr(int rn, double *p); | 
|  | extern void put_fpr(int rn, const double *p); | 
|  | extern void get_vr(int rn, __vector128 *p); | 
|  | extern void put_vr(int rn, __vector128 *p); | 
|  | extern void load_vsrn(int vsr, const void *p); | 
|  | extern void store_vsrn(int vsr, void *p); | 
|  | extern void conv_sp_to_dp(const float *sp, double *dp); | 
|  | extern void conv_dp_to_sp(const double *dp, float *sp); | 
|  | #endif | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | /* | 
|  | * Functions in quad.S | 
|  | */ | 
|  | extern int do_lq(unsigned long ea, unsigned long *regs); | 
|  | extern int do_stq(unsigned long ea, unsigned long val0, unsigned long val1); | 
|  | extern int do_lqarx(unsigned long ea, unsigned long *regs); | 
|  | extern int do_stqcx(unsigned long ea, unsigned long val0, unsigned long val1, | 
|  | unsigned int *crp); | 
|  | #endif | 
|  |  | 
|  | #ifdef __LITTLE_ENDIAN__ | 
|  | #define IS_LE	1 | 
|  | #define IS_BE	0 | 
|  | #else | 
|  | #define IS_LE	0 | 
|  | #define IS_BE	1 | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * Emulate the truncation of 64 bit values in 32-bit mode. | 
|  | */ | 
|  | static nokprobe_inline unsigned long truncate_if_32bit(unsigned long msr, | 
|  | unsigned long val) | 
|  | { | 
|  | #ifdef __powerpc64__ | 
|  | if ((msr & MSR_64BIT) == 0) | 
|  | val &= 0xffffffffUL; | 
|  | #endif | 
|  | return val; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Determine whether a conditional branch instruction would branch. | 
|  | */ | 
|  | static nokprobe_inline int branch_taken(unsigned int instr, | 
|  | const struct pt_regs *regs, | 
|  | struct instruction_op *op) | 
|  | { | 
|  | unsigned int bo = (instr >> 21) & 0x1f; | 
|  | unsigned int bi; | 
|  |  | 
|  | if ((bo & 4) == 0) { | 
|  | /* decrement counter */ | 
|  | op->type |= DECCTR; | 
|  | if (((bo >> 1) & 1) ^ (regs->ctr == 1)) | 
|  | return 0; | 
|  | } | 
|  | if ((bo & 0x10) == 0) { | 
|  | /* check bit from CR */ | 
|  | bi = (instr >> 16) & 0x1f; | 
|  | if (((regs->ccr >> (31 - bi)) & 1) != ((bo >> 3) & 1)) | 
|  | return 0; | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | static nokprobe_inline long address_ok(struct pt_regs *regs, | 
|  | unsigned long ea, int nb) | 
|  | { | 
|  | if (!user_mode(regs)) | 
|  | return 1; | 
|  | if (__access_ok(ea, nb, USER_DS)) | 
|  | return 1; | 
|  | if (__access_ok(ea, 1, USER_DS)) | 
|  | /* Access overlaps the end of the user region */ | 
|  | regs->dar = USER_DS.seg; | 
|  | else | 
|  | regs->dar = ea; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Calculate effective address for a D-form instruction | 
|  | */ | 
|  | static nokprobe_inline unsigned long dform_ea(unsigned int instr, | 
|  | const struct pt_regs *regs) | 
|  | { | 
|  | int ra; | 
|  | unsigned long ea; | 
|  |  | 
|  | ra = (instr >> 16) & 0x1f; | 
|  | ea = (signed short) instr;		/* sign-extend */ | 
|  | if (ra) | 
|  | ea += regs->gpr[ra]; | 
|  |  | 
|  | return ea; | 
|  | } | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | /* | 
|  | * Calculate effective address for a DS-form instruction | 
|  | */ | 
|  | static nokprobe_inline unsigned long dsform_ea(unsigned int instr, | 
|  | const struct pt_regs *regs) | 
|  | { | 
|  | int ra; | 
|  | unsigned long ea; | 
|  |  | 
|  | ra = (instr >> 16) & 0x1f; | 
|  | ea = (signed short) (instr & ~3);	/* sign-extend */ | 
|  | if (ra) | 
|  | ea += regs->gpr[ra]; | 
|  |  | 
|  | return ea; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Calculate effective address for a DQ-form instruction | 
|  | */ | 
|  | static nokprobe_inline unsigned long dqform_ea(unsigned int instr, | 
|  | const struct pt_regs *regs) | 
|  | { | 
|  | int ra; | 
|  | unsigned long ea; | 
|  |  | 
|  | ra = (instr >> 16) & 0x1f; | 
|  | ea = (signed short) (instr & ~0xf);	/* sign-extend */ | 
|  | if (ra) | 
|  | ea += regs->gpr[ra]; | 
|  |  | 
|  | return ea; | 
|  | } | 
|  | #endif /* __powerpc64 */ | 
|  |  | 
|  | /* | 
|  | * Calculate effective address for an X-form instruction | 
|  | */ | 
|  | static nokprobe_inline unsigned long xform_ea(unsigned int instr, | 
|  | const struct pt_regs *regs) | 
|  | { | 
|  | int ra, rb; | 
|  | unsigned long ea; | 
|  |  | 
|  | ra = (instr >> 16) & 0x1f; | 
|  | rb = (instr >> 11) & 0x1f; | 
|  | ea = regs->gpr[rb]; | 
|  | if (ra) | 
|  | ea += regs->gpr[ra]; | 
|  |  | 
|  | return ea; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Return the largest power of 2, not greater than sizeof(unsigned long), | 
|  | * such that x is a multiple of it. | 
|  | */ | 
|  | static nokprobe_inline unsigned long max_align(unsigned long x) | 
|  | { | 
|  | x |= sizeof(unsigned long); | 
|  | return x & -x;		/* isolates rightmost bit */ | 
|  | } | 
|  |  | 
|  | static nokprobe_inline unsigned long byterev_2(unsigned long x) | 
|  | { | 
|  | return ((x >> 8) & 0xff) | ((x & 0xff) << 8); | 
|  | } | 
|  |  | 
|  | static nokprobe_inline unsigned long byterev_4(unsigned long x) | 
|  | { | 
|  | return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) | | 
|  | ((x & 0xff00) << 8) | ((x & 0xff) << 24); | 
|  | } | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | static nokprobe_inline unsigned long byterev_8(unsigned long x) | 
|  | { | 
|  | return (byterev_4(x) << 32) | byterev_4(x >> 32); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | static nokprobe_inline void do_byte_reverse(void *ptr, int nb) | 
|  | { | 
|  | switch (nb) { | 
|  | case 2: | 
|  | *(u16 *)ptr = byterev_2(*(u16 *)ptr); | 
|  | break; | 
|  | case 4: | 
|  | *(u32 *)ptr = byterev_4(*(u32 *)ptr); | 
|  | break; | 
|  | #ifdef __powerpc64__ | 
|  | case 8: | 
|  | *(unsigned long *)ptr = byterev_8(*(unsigned long *)ptr); | 
|  | break; | 
|  | case 16: { | 
|  | unsigned long *up = (unsigned long *)ptr; | 
|  | unsigned long tmp; | 
|  | tmp = byterev_8(up[0]); | 
|  | up[0] = byterev_8(up[1]); | 
|  | up[1] = tmp; | 
|  | break; | 
|  | } | 
|  | #endif | 
|  | default: | 
|  | WARN_ON_ONCE(1); | 
|  | } | 
|  | } | 
|  |  | 
|  | static nokprobe_inline int read_mem_aligned(unsigned long *dest, | 
|  | unsigned long ea, int nb, | 
|  | struct pt_regs *regs) | 
|  | { | 
|  | int err = 0; | 
|  | unsigned long x = 0; | 
|  |  | 
|  | switch (nb) { | 
|  | case 1: | 
|  | err = __get_user(x, (unsigned char __user *) ea); | 
|  | break; | 
|  | case 2: | 
|  | err = __get_user(x, (unsigned short __user *) ea); | 
|  | break; | 
|  | case 4: | 
|  | err = __get_user(x, (unsigned int __user *) ea); | 
|  | break; | 
|  | #ifdef __powerpc64__ | 
|  | case 8: | 
|  | err = __get_user(x, (unsigned long __user *) ea); | 
|  | break; | 
|  | #endif | 
|  | } | 
|  | if (!err) | 
|  | *dest = x; | 
|  | else | 
|  | regs->dar = ea; | 
|  | return err; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Copy from userspace to a buffer, using the largest possible | 
|  | * aligned accesses, up to sizeof(long). | 
|  | */ | 
|  | static nokprobe_inline int copy_mem_in(u8 *dest, unsigned long ea, int nb, | 
|  | struct pt_regs *regs) | 
|  | { | 
|  | int err = 0; | 
|  | int c; | 
|  |  | 
|  | for (; nb > 0; nb -= c) { | 
|  | c = max_align(ea); | 
|  | if (c > nb) | 
|  | c = max_align(nb); | 
|  | switch (c) { | 
|  | case 1: | 
|  | err = __get_user(*dest, (unsigned char __user *) ea); | 
|  | break; | 
|  | case 2: | 
|  | err = __get_user(*(u16 *)dest, | 
|  | (unsigned short __user *) ea); | 
|  | break; | 
|  | case 4: | 
|  | err = __get_user(*(u32 *)dest, | 
|  | (unsigned int __user *) ea); | 
|  | break; | 
|  | #ifdef __powerpc64__ | 
|  | case 8: | 
|  | err = __get_user(*(unsigned long *)dest, | 
|  | (unsigned long __user *) ea); | 
|  | break; | 
|  | #endif | 
|  | } | 
|  | if (err) { | 
|  | regs->dar = ea; | 
|  | return err; | 
|  | } | 
|  | dest += c; | 
|  | ea += c; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static nokprobe_inline int read_mem_unaligned(unsigned long *dest, | 
|  | unsigned long ea, int nb, | 
|  | struct pt_regs *regs) | 
|  | { | 
|  | union { | 
|  | unsigned long ul; | 
|  | u8 b[sizeof(unsigned long)]; | 
|  | } u; | 
|  | int i; | 
|  | int err; | 
|  |  | 
|  | u.ul = 0; | 
|  | i = IS_BE ? sizeof(unsigned long) - nb : 0; | 
|  | err = copy_mem_in(&u.b[i], ea, nb, regs); | 
|  | if (!err) | 
|  | *dest = u.ul; | 
|  | return err; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Read memory at address ea for nb bytes, return 0 for success | 
|  | * or -EFAULT if an error occurred.  N.B. nb must be 1, 2, 4 or 8. | 
|  | * If nb < sizeof(long), the result is right-justified on BE systems. | 
|  | */ | 
|  | static int read_mem(unsigned long *dest, unsigned long ea, int nb, | 
|  | struct pt_regs *regs) | 
|  | { | 
|  | if (!address_ok(regs, ea, nb)) | 
|  | return -EFAULT; | 
|  | if ((ea & (nb - 1)) == 0) | 
|  | return read_mem_aligned(dest, ea, nb, regs); | 
|  | return read_mem_unaligned(dest, ea, nb, regs); | 
|  | } | 
|  | NOKPROBE_SYMBOL(read_mem); | 
|  |  | 
|  | static nokprobe_inline int write_mem_aligned(unsigned long val, | 
|  | unsigned long ea, int nb, | 
|  | struct pt_regs *regs) | 
|  | { | 
|  | int err = 0; | 
|  |  | 
|  | switch (nb) { | 
|  | case 1: | 
|  | err = __put_user(val, (unsigned char __user *) ea); | 
|  | break; | 
|  | case 2: | 
|  | err = __put_user(val, (unsigned short __user *) ea); | 
|  | break; | 
|  | case 4: | 
|  | err = __put_user(val, (unsigned int __user *) ea); | 
|  | break; | 
|  | #ifdef __powerpc64__ | 
|  | case 8: | 
|  | err = __put_user(val, (unsigned long __user *) ea); | 
|  | break; | 
|  | #endif | 
|  | } | 
|  | if (err) | 
|  | regs->dar = ea; | 
|  | return err; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Copy from a buffer to userspace, using the largest possible | 
|  | * aligned accesses, up to sizeof(long). | 
|  | */ | 
|  | static nokprobe_inline int copy_mem_out(u8 *dest, unsigned long ea, int nb, | 
|  | struct pt_regs *regs) | 
|  | { | 
|  | int err = 0; | 
|  | int c; | 
|  |  | 
|  | for (; nb > 0; nb -= c) { | 
|  | c = max_align(ea); | 
|  | if (c > nb) | 
|  | c = max_align(nb); | 
|  | switch (c) { | 
|  | case 1: | 
|  | err = __put_user(*dest, (unsigned char __user *) ea); | 
|  | break; | 
|  | case 2: | 
|  | err = __put_user(*(u16 *)dest, | 
|  | (unsigned short __user *) ea); | 
|  | break; | 
|  | case 4: | 
|  | err = __put_user(*(u32 *)dest, | 
|  | (unsigned int __user *) ea); | 
|  | break; | 
|  | #ifdef __powerpc64__ | 
|  | case 8: | 
|  | err = __put_user(*(unsigned long *)dest, | 
|  | (unsigned long __user *) ea); | 
|  | break; | 
|  | #endif | 
|  | } | 
|  | if (err) { | 
|  | regs->dar = ea; | 
|  | return err; | 
|  | } | 
|  | dest += c; | 
|  | ea += c; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static nokprobe_inline int write_mem_unaligned(unsigned long val, | 
|  | unsigned long ea, int nb, | 
|  | struct pt_regs *regs) | 
|  | { | 
|  | union { | 
|  | unsigned long ul; | 
|  | u8 b[sizeof(unsigned long)]; | 
|  | } u; | 
|  | int i; | 
|  |  | 
|  | u.ul = val; | 
|  | i = IS_BE ? sizeof(unsigned long) - nb : 0; | 
|  | return copy_mem_out(&u.b[i], ea, nb, regs); | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Write memory at address ea for nb bytes, return 0 for success | 
|  | * or -EFAULT if an error occurred.  N.B. nb must be 1, 2, 4 or 8. | 
|  | */ | 
|  | static int write_mem(unsigned long val, unsigned long ea, int nb, | 
|  | struct pt_regs *regs) | 
|  | { | 
|  | if (!address_ok(regs, ea, nb)) | 
|  | return -EFAULT; | 
|  | if ((ea & (nb - 1)) == 0) | 
|  | return write_mem_aligned(val, ea, nb, regs); | 
|  | return write_mem_unaligned(val, ea, nb, regs); | 
|  | } | 
|  | NOKPROBE_SYMBOL(write_mem); | 
|  |  | 
|  | #ifdef CONFIG_PPC_FPU | 
|  | /* | 
|  | * These access either the real FP register or the image in the | 
|  | * thread_struct, depending on regs->msr & MSR_FP. | 
|  | */ | 
|  | static int do_fp_load(struct instruction_op *op, unsigned long ea, | 
|  | struct pt_regs *regs, bool cross_endian) | 
|  | { | 
|  | int err, rn, nb; | 
|  | union { | 
|  | int i; | 
|  | unsigned int u; | 
|  | float f; | 
|  | double d[2]; | 
|  | unsigned long l[2]; | 
|  | u8 b[2 * sizeof(double)]; | 
|  | } u; | 
|  |  | 
|  | nb = GETSIZE(op->type); | 
|  | if (!address_ok(regs, ea, nb)) | 
|  | return -EFAULT; | 
|  | rn = op->reg; | 
|  | err = copy_mem_in(u.b, ea, nb, regs); | 
|  | if (err) | 
|  | return err; | 
|  | if (unlikely(cross_endian)) { | 
|  | do_byte_reverse(u.b, min(nb, 8)); | 
|  | if (nb == 16) | 
|  | do_byte_reverse(&u.b[8], 8); | 
|  | } | 
|  | preempt_disable(); | 
|  | if (nb == 4) { | 
|  | if (op->type & FPCONV) | 
|  | conv_sp_to_dp(&u.f, &u.d[0]); | 
|  | else if (op->type & SIGNEXT) | 
|  | u.l[0] = u.i; | 
|  | else | 
|  | u.l[0] = u.u; | 
|  | } | 
|  | if (regs->msr & MSR_FP) | 
|  | put_fpr(rn, &u.d[0]); | 
|  | else | 
|  | current->thread.TS_FPR(rn) = u.l[0]; | 
|  | if (nb == 16) { | 
|  | /* lfdp */ | 
|  | rn |= 1; | 
|  | if (regs->msr & MSR_FP) | 
|  | put_fpr(rn, &u.d[1]); | 
|  | else | 
|  | current->thread.TS_FPR(rn) = u.l[1]; | 
|  | } | 
|  | preempt_enable(); | 
|  | return 0; | 
|  | } | 
|  | NOKPROBE_SYMBOL(do_fp_load); | 
|  |  | 
|  | static int do_fp_store(struct instruction_op *op, unsigned long ea, | 
|  | struct pt_regs *regs, bool cross_endian) | 
|  | { | 
|  | int rn, nb; | 
|  | union { | 
|  | unsigned int u; | 
|  | float f; | 
|  | double d[2]; | 
|  | unsigned long l[2]; | 
|  | u8 b[2 * sizeof(double)]; | 
|  | } u; | 
|  |  | 
|  | nb = GETSIZE(op->type); | 
|  | if (!address_ok(regs, ea, nb)) | 
|  | return -EFAULT; | 
|  | rn = op->reg; | 
|  | preempt_disable(); | 
|  | if (regs->msr & MSR_FP) | 
|  | get_fpr(rn, &u.d[0]); | 
|  | else | 
|  | u.l[0] = current->thread.TS_FPR(rn); | 
|  | if (nb == 4) { | 
|  | if (op->type & FPCONV) | 
|  | conv_dp_to_sp(&u.d[0], &u.f); | 
|  | else | 
|  | u.u = u.l[0]; | 
|  | } | 
|  | if (nb == 16) { | 
|  | rn |= 1; | 
|  | if (regs->msr & MSR_FP) | 
|  | get_fpr(rn, &u.d[1]); | 
|  | else | 
|  | u.l[1] = current->thread.TS_FPR(rn); | 
|  | } | 
|  | preempt_enable(); | 
|  | if (unlikely(cross_endian)) { | 
|  | do_byte_reverse(u.b, min(nb, 8)); | 
|  | if (nb == 16) | 
|  | do_byte_reverse(&u.b[8], 8); | 
|  | } | 
|  | return copy_mem_out(u.b, ea, nb, regs); | 
|  | } | 
|  | NOKPROBE_SYMBOL(do_fp_store); | 
|  | #endif | 
|  |  | 
|  | #ifdef CONFIG_ALTIVEC | 
|  | /* For Altivec/VMX, no need to worry about alignment */ | 
|  | static nokprobe_inline int do_vec_load(int rn, unsigned long ea, | 
|  | int size, struct pt_regs *regs, | 
|  | bool cross_endian) | 
|  | { | 
|  | int err; | 
|  | union { | 
|  | __vector128 v; | 
|  | u8 b[sizeof(__vector128)]; | 
|  | } u = {}; | 
|  |  | 
|  | if (!address_ok(regs, ea & ~0xfUL, 16)) | 
|  | return -EFAULT; | 
|  | /* align to multiple of size */ | 
|  | ea &= ~(size - 1); | 
|  | err = copy_mem_in(&u.b[ea & 0xf], ea, size, regs); | 
|  | if (err) | 
|  | return err; | 
|  | if (unlikely(cross_endian)) | 
|  | do_byte_reverse(&u.b[ea & 0xf], size); | 
|  | preempt_disable(); | 
|  | if (regs->msr & MSR_VEC) | 
|  | put_vr(rn, &u.v); | 
|  | else | 
|  | current->thread.vr_state.vr[rn] = u.v; | 
|  | preempt_enable(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static nokprobe_inline int do_vec_store(int rn, unsigned long ea, | 
|  | int size, struct pt_regs *regs, | 
|  | bool cross_endian) | 
|  | { | 
|  | union { | 
|  | __vector128 v; | 
|  | u8 b[sizeof(__vector128)]; | 
|  | } u; | 
|  |  | 
|  | if (!address_ok(regs, ea & ~0xfUL, 16)) | 
|  | return -EFAULT; | 
|  | /* align to multiple of size */ | 
|  | ea &= ~(size - 1); | 
|  |  | 
|  | preempt_disable(); | 
|  | if (regs->msr & MSR_VEC) | 
|  | get_vr(rn, &u.v); | 
|  | else | 
|  | u.v = current->thread.vr_state.vr[rn]; | 
|  | preempt_enable(); | 
|  | if (unlikely(cross_endian)) | 
|  | do_byte_reverse(&u.b[ea & 0xf], size); | 
|  | return copy_mem_out(&u.b[ea & 0xf], ea, size, regs); | 
|  | } | 
|  | #endif /* CONFIG_ALTIVEC */ | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | static nokprobe_inline int emulate_lq(struct pt_regs *regs, unsigned long ea, | 
|  | int reg, bool cross_endian) | 
|  | { | 
|  | int err; | 
|  |  | 
|  | if (!address_ok(regs, ea, 16)) | 
|  | return -EFAULT; | 
|  | /* if aligned, should be atomic */ | 
|  | if ((ea & 0xf) == 0) { | 
|  | err = do_lq(ea, ®s->gpr[reg]); | 
|  | } else { | 
|  | err = read_mem(®s->gpr[reg + IS_LE], ea, 8, regs); | 
|  | if (!err) | 
|  | err = read_mem(®s->gpr[reg + IS_BE], ea + 8, 8, regs); | 
|  | } | 
|  | if (!err && unlikely(cross_endian)) | 
|  | do_byte_reverse(®s->gpr[reg], 16); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | static nokprobe_inline int emulate_stq(struct pt_regs *regs, unsigned long ea, | 
|  | int reg, bool cross_endian) | 
|  | { | 
|  | int err; | 
|  | unsigned long vals[2]; | 
|  |  | 
|  | if (!address_ok(regs, ea, 16)) | 
|  | return -EFAULT; | 
|  | vals[0] = regs->gpr[reg]; | 
|  | vals[1] = regs->gpr[reg + 1]; | 
|  | if (unlikely(cross_endian)) | 
|  | do_byte_reverse(vals, 16); | 
|  |  | 
|  | /* if aligned, should be atomic */ | 
|  | if ((ea & 0xf) == 0) | 
|  | return do_stq(ea, vals[0], vals[1]); | 
|  |  | 
|  | err = write_mem(vals[IS_LE], ea, 8, regs); | 
|  | if (!err) | 
|  | err = write_mem(vals[IS_BE], ea + 8, 8, regs); | 
|  | return err; | 
|  | } | 
|  | #endif /* __powerpc64 */ | 
|  |  | 
|  | #ifdef CONFIG_VSX | 
|  | void emulate_vsx_load(struct instruction_op *op, union vsx_reg *reg, | 
|  | const void *mem, bool rev) | 
|  | { | 
|  | int size, read_size; | 
|  | int i, j; | 
|  | const unsigned int *wp; | 
|  | const unsigned short *hp; | 
|  | const unsigned char *bp; | 
|  |  | 
|  | size = GETSIZE(op->type); | 
|  | reg->d[0] = reg->d[1] = 0; | 
|  |  | 
|  | switch (op->element_size) { | 
|  | case 16: | 
|  | /* whole vector; lxv[x] or lxvl[l] */ | 
|  | if (size == 0) | 
|  | break; | 
|  | memcpy(reg, mem, size); | 
|  | if (IS_LE && (op->vsx_flags & VSX_LDLEFT)) | 
|  | rev = !rev; | 
|  | if (rev) | 
|  | do_byte_reverse(reg, 16); | 
|  | break; | 
|  | case 8: | 
|  | /* scalar loads, lxvd2x, lxvdsx */ | 
|  | read_size = (size >= 8) ? 8 : size; | 
|  | i = IS_LE ? 8 : 8 - read_size; | 
|  | memcpy(®->b[i], mem, read_size); | 
|  | if (rev) | 
|  | do_byte_reverse(®->b[i], 8); | 
|  | if (size < 8) { | 
|  | if (op->type & SIGNEXT) { | 
|  | /* size == 4 is the only case here */ | 
|  | reg->d[IS_LE] = (signed int) reg->d[IS_LE]; | 
|  | } else if (op->vsx_flags & VSX_FPCONV) { | 
|  | preempt_disable(); | 
|  | conv_sp_to_dp(®->fp[1 + IS_LE], | 
|  | ®->dp[IS_LE]); | 
|  | preempt_enable(); | 
|  | } | 
|  | } else { | 
|  | if (size == 16) { | 
|  | unsigned long v = *(unsigned long *)(mem + 8); | 
|  | reg->d[IS_BE] = !rev ? v : byterev_8(v); | 
|  | } else if (op->vsx_flags & VSX_SPLAT) | 
|  | reg->d[IS_BE] = reg->d[IS_LE]; | 
|  | } | 
|  | break; | 
|  | case 4: | 
|  | /* lxvw4x, lxvwsx */ | 
|  | wp = mem; | 
|  | for (j = 0; j < size / 4; ++j) { | 
|  | i = IS_LE ? 3 - j : j; | 
|  | reg->w[i] = !rev ? *wp++ : byterev_4(*wp++); | 
|  | } | 
|  | if (op->vsx_flags & VSX_SPLAT) { | 
|  | u32 val = reg->w[IS_LE ? 3 : 0]; | 
|  | for (; j < 4; ++j) { | 
|  | i = IS_LE ? 3 - j : j; | 
|  | reg->w[i] = val; | 
|  | } | 
|  | } | 
|  | break; | 
|  | case 2: | 
|  | /* lxvh8x */ | 
|  | hp = mem; | 
|  | for (j = 0; j < size / 2; ++j) { | 
|  | i = IS_LE ? 7 - j : j; | 
|  | reg->h[i] = !rev ? *hp++ : byterev_2(*hp++); | 
|  | } | 
|  | break; | 
|  | case 1: | 
|  | /* lxvb16x */ | 
|  | bp = mem; | 
|  | for (j = 0; j < size; ++j) { | 
|  | i = IS_LE ? 15 - j : j; | 
|  | reg->b[i] = *bp++; | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(emulate_vsx_load); | 
|  | NOKPROBE_SYMBOL(emulate_vsx_load); | 
|  |  | 
|  | void emulate_vsx_store(struct instruction_op *op, const union vsx_reg *reg, | 
|  | void *mem, bool rev) | 
|  | { | 
|  | int size, write_size; | 
|  | int i, j; | 
|  | union vsx_reg buf; | 
|  | unsigned int *wp; | 
|  | unsigned short *hp; | 
|  | unsigned char *bp; | 
|  |  | 
|  | size = GETSIZE(op->type); | 
|  |  | 
|  | switch (op->element_size) { | 
|  | case 16: | 
|  | /* stxv, stxvx, stxvl, stxvll */ | 
|  | if (size == 0) | 
|  | break; | 
|  | if (IS_LE && (op->vsx_flags & VSX_LDLEFT)) | 
|  | rev = !rev; | 
|  | if (rev) { | 
|  | /* reverse 16 bytes */ | 
|  | buf.d[0] = byterev_8(reg->d[1]); | 
|  | buf.d[1] = byterev_8(reg->d[0]); | 
|  | reg = &buf; | 
|  | } | 
|  | memcpy(mem, reg, size); | 
|  | break; | 
|  | case 8: | 
|  | /* scalar stores, stxvd2x */ | 
|  | write_size = (size >= 8) ? 8 : size; | 
|  | i = IS_LE ? 8 : 8 - write_size; | 
|  | if (size < 8 && op->vsx_flags & VSX_FPCONV) { | 
|  | buf.d[0] = buf.d[1] = 0; | 
|  | preempt_disable(); | 
|  | conv_dp_to_sp(®->dp[IS_LE], &buf.fp[1 + IS_LE]); | 
|  | preempt_enable(); | 
|  | reg = &buf; | 
|  | } | 
|  | memcpy(mem, ®->b[i], write_size); | 
|  | if (size == 16) | 
|  | memcpy(mem + 8, ®->d[IS_BE], 8); | 
|  | if (unlikely(rev)) { | 
|  | do_byte_reverse(mem, write_size); | 
|  | if (size == 16) | 
|  | do_byte_reverse(mem + 8, 8); | 
|  | } | 
|  | break; | 
|  | case 4: | 
|  | /* stxvw4x */ | 
|  | wp = mem; | 
|  | for (j = 0; j < size / 4; ++j) { | 
|  | i = IS_LE ? 3 - j : j; | 
|  | *wp++ = !rev ? reg->w[i] : byterev_4(reg->w[i]); | 
|  | } | 
|  | break; | 
|  | case 2: | 
|  | /* stxvh8x */ | 
|  | hp = mem; | 
|  | for (j = 0; j < size / 2; ++j) { | 
|  | i = IS_LE ? 7 - j : j; | 
|  | *hp++ = !rev ? reg->h[i] : byterev_2(reg->h[i]); | 
|  | } | 
|  | break; | 
|  | case 1: | 
|  | /* stvxb16x */ | 
|  | bp = mem; | 
|  | for (j = 0; j < size; ++j) { | 
|  | i = IS_LE ? 15 - j : j; | 
|  | *bp++ = reg->b[i]; | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(emulate_vsx_store); | 
|  | NOKPROBE_SYMBOL(emulate_vsx_store); | 
|  |  | 
|  | static nokprobe_inline int do_vsx_load(struct instruction_op *op, | 
|  | unsigned long ea, struct pt_regs *regs, | 
|  | bool cross_endian) | 
|  | { | 
|  | int reg = op->reg; | 
|  | u8 mem[16]; | 
|  | union vsx_reg buf; | 
|  | int size = GETSIZE(op->type); | 
|  |  | 
|  | if (!address_ok(regs, ea, size) || copy_mem_in(mem, ea, size, regs)) | 
|  | return -EFAULT; | 
|  |  | 
|  | emulate_vsx_load(op, &buf, mem, cross_endian); | 
|  | preempt_disable(); | 
|  | if (reg < 32) { | 
|  | /* FP regs + extensions */ | 
|  | if (regs->msr & MSR_FP) { | 
|  | load_vsrn(reg, &buf); | 
|  | } else { | 
|  | current->thread.fp_state.fpr[reg][0] = buf.d[0]; | 
|  | current->thread.fp_state.fpr[reg][1] = buf.d[1]; | 
|  | } | 
|  | } else { | 
|  | if (regs->msr & MSR_VEC) | 
|  | load_vsrn(reg, &buf); | 
|  | else | 
|  | current->thread.vr_state.vr[reg - 32] = buf.v; | 
|  | } | 
|  | preempt_enable(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static nokprobe_inline int do_vsx_store(struct instruction_op *op, | 
|  | unsigned long ea, struct pt_regs *regs, | 
|  | bool cross_endian) | 
|  | { | 
|  | int reg = op->reg; | 
|  | u8 mem[16]; | 
|  | union vsx_reg buf; | 
|  | int size = GETSIZE(op->type); | 
|  |  | 
|  | if (!address_ok(regs, ea, size)) | 
|  | return -EFAULT; | 
|  |  | 
|  | preempt_disable(); | 
|  | if (reg < 32) { | 
|  | /* FP regs + extensions */ | 
|  | if (regs->msr & MSR_FP) { | 
|  | store_vsrn(reg, &buf); | 
|  | } else { | 
|  | buf.d[0] = current->thread.fp_state.fpr[reg][0]; | 
|  | buf.d[1] = current->thread.fp_state.fpr[reg][1]; | 
|  | } | 
|  | } else { | 
|  | if (regs->msr & MSR_VEC) | 
|  | store_vsrn(reg, &buf); | 
|  | else | 
|  | buf.v = current->thread.vr_state.vr[reg - 32]; | 
|  | } | 
|  | preempt_enable(); | 
|  | emulate_vsx_store(op, &buf, mem, cross_endian); | 
|  | return  copy_mem_out(mem, ea, size, regs); | 
|  | } | 
|  | #endif /* CONFIG_VSX */ | 
|  |  | 
|  | int emulate_dcbz(unsigned long ea, struct pt_regs *regs) | 
|  | { | 
|  | int err; | 
|  | unsigned long i, size; | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | size = ppc64_caches.l1d.block_size; | 
|  | if (!(regs->msr & MSR_64BIT)) | 
|  | ea &= 0xffffffffUL; | 
|  | #else | 
|  | size = L1_CACHE_BYTES; | 
|  | #endif | 
|  | ea &= ~(size - 1); | 
|  | if (!address_ok(regs, ea, size)) | 
|  | return -EFAULT; | 
|  | for (i = 0; i < size; i += sizeof(long)) { | 
|  | err = __put_user(0, (unsigned long __user *) (ea + i)); | 
|  | if (err) { | 
|  | regs->dar = ea; | 
|  | return err; | 
|  | } | 
|  | } | 
|  | return 0; | 
|  | } | 
|  | NOKPROBE_SYMBOL(emulate_dcbz); | 
|  |  | 
|  | #define __put_user_asmx(x, addr, err, op, cr)		\ | 
|  | __asm__ __volatile__(				\ | 
|  | "1:	" op " %2,0,%3\n"		\ | 
|  | "	mfcr	%1\n"			\ | 
|  | "2:\n"					\ | 
|  | ".section .fixup,\"ax\"\n"		\ | 
|  | "3:	li	%0,%4\n"		\ | 
|  | "	b	2b\n"			\ | 
|  | ".previous\n"				\ | 
|  | EX_TABLE(1b, 3b)			\ | 
|  | : "=r" (err), "=r" (cr)			\ | 
|  | : "r" (x), "r" (addr), "i" (-EFAULT), "0" (err)) | 
|  |  | 
|  | #define __get_user_asmx(x, addr, err, op)		\ | 
|  | __asm__ __volatile__(				\ | 
|  | "1:	"op" %1,0,%2\n"			\ | 
|  | "2:\n"					\ | 
|  | ".section .fixup,\"ax\"\n"		\ | 
|  | "3:	li	%0,%3\n"		\ | 
|  | "	b	2b\n"			\ | 
|  | ".previous\n"				\ | 
|  | EX_TABLE(1b, 3b)			\ | 
|  | : "=r" (err), "=r" (x)			\ | 
|  | : "r" (addr), "i" (-EFAULT), "0" (err)) | 
|  |  | 
|  | #define __cacheop_user_asmx(addr, err, op)		\ | 
|  | __asm__ __volatile__(				\ | 
|  | "1:	"op" 0,%1\n"			\ | 
|  | "2:\n"					\ | 
|  | ".section .fixup,\"ax\"\n"		\ | 
|  | "3:	li	%0,%3\n"		\ | 
|  | "	b	2b\n"			\ | 
|  | ".previous\n"				\ | 
|  | EX_TABLE(1b, 3b)			\ | 
|  | : "=r" (err)				\ | 
|  | : "r" (addr), "i" (-EFAULT), "0" (err)) | 
|  |  | 
|  | static nokprobe_inline void set_cr0(const struct pt_regs *regs, | 
|  | struct instruction_op *op) | 
|  | { | 
|  | long val = op->val; | 
|  |  | 
|  | op->type |= SETCC; | 
|  | op->ccval = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000); | 
|  | #ifdef __powerpc64__ | 
|  | if (!(regs->msr & MSR_64BIT)) | 
|  | val = (int) val; | 
|  | #endif | 
|  | if (val < 0) | 
|  | op->ccval |= 0x80000000; | 
|  | else if (val > 0) | 
|  | op->ccval |= 0x40000000; | 
|  | else | 
|  | op->ccval |= 0x20000000; | 
|  | } | 
|  |  | 
|  | static nokprobe_inline void set_ca32(struct instruction_op *op, bool val) | 
|  | { | 
|  | if (cpu_has_feature(CPU_FTR_ARCH_300)) { | 
|  | if (val) | 
|  | op->xerval |= XER_CA32; | 
|  | else | 
|  | op->xerval &= ~XER_CA32; | 
|  | } | 
|  | } | 
|  |  | 
|  | static nokprobe_inline void add_with_carry(const struct pt_regs *regs, | 
|  | struct instruction_op *op, int rd, | 
|  | unsigned long val1, unsigned long val2, | 
|  | unsigned long carry_in) | 
|  | { | 
|  | unsigned long val = val1 + val2; | 
|  |  | 
|  | if (carry_in) | 
|  | ++val; | 
|  | op->type = COMPUTE + SETREG + SETXER; | 
|  | op->reg = rd; | 
|  | op->val = val; | 
|  | #ifdef __powerpc64__ | 
|  | if (!(regs->msr & MSR_64BIT)) { | 
|  | val = (unsigned int) val; | 
|  | val1 = (unsigned int) val1; | 
|  | } | 
|  | #endif | 
|  | op->xerval = regs->xer; | 
|  | if (val < val1 || (carry_in && val == val1)) | 
|  | op->xerval |= XER_CA; | 
|  | else | 
|  | op->xerval &= ~XER_CA; | 
|  |  | 
|  | set_ca32(op, (unsigned int)val < (unsigned int)val1 || | 
|  | (carry_in && (unsigned int)val == (unsigned int)val1)); | 
|  | } | 
|  |  | 
|  | static nokprobe_inline void do_cmp_signed(const struct pt_regs *regs, | 
|  | struct instruction_op *op, | 
|  | long v1, long v2, int crfld) | 
|  | { | 
|  | unsigned int crval, shift; | 
|  |  | 
|  | op->type = COMPUTE + SETCC; | 
|  | crval = (regs->xer >> 31) & 1;		/* get SO bit */ | 
|  | if (v1 < v2) | 
|  | crval |= 8; | 
|  | else if (v1 > v2) | 
|  | crval |= 4; | 
|  | else | 
|  | crval |= 2; | 
|  | shift = (7 - crfld) * 4; | 
|  | op->ccval = (regs->ccr & ~(0xf << shift)) | (crval << shift); | 
|  | } | 
|  |  | 
|  | static nokprobe_inline void do_cmp_unsigned(const struct pt_regs *regs, | 
|  | struct instruction_op *op, | 
|  | unsigned long v1, | 
|  | unsigned long v2, int crfld) | 
|  | { | 
|  | unsigned int crval, shift; | 
|  |  | 
|  | op->type = COMPUTE + SETCC; | 
|  | crval = (regs->xer >> 31) & 1;		/* get SO bit */ | 
|  | if (v1 < v2) | 
|  | crval |= 8; | 
|  | else if (v1 > v2) | 
|  | crval |= 4; | 
|  | else | 
|  | crval |= 2; | 
|  | shift = (7 - crfld) * 4; | 
|  | op->ccval = (regs->ccr & ~(0xf << shift)) | (crval << shift); | 
|  | } | 
|  |  | 
|  | static nokprobe_inline void do_cmpb(const struct pt_regs *regs, | 
|  | struct instruction_op *op, | 
|  | unsigned long v1, unsigned long v2) | 
|  | { | 
|  | unsigned long long out_val, mask; | 
|  | int i; | 
|  |  | 
|  | out_val = 0; | 
|  | for (i = 0; i < 8; i++) { | 
|  | mask = 0xffUL << (i * 8); | 
|  | if ((v1 & mask) == (v2 & mask)) | 
|  | out_val |= mask; | 
|  | } | 
|  | op->val = out_val; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * The size parameter is used to adjust the equivalent popcnt instruction. | 
|  | * popcntb = 8, popcntw = 32, popcntd = 64 | 
|  | */ | 
|  | static nokprobe_inline void do_popcnt(const struct pt_regs *regs, | 
|  | struct instruction_op *op, | 
|  | unsigned long v1, int size) | 
|  | { | 
|  | unsigned long long out = v1; | 
|  |  | 
|  | out -= (out >> 1) & 0x5555555555555555ULL; | 
|  | out = (0x3333333333333333ULL & out) + | 
|  | (0x3333333333333333ULL & (out >> 2)); | 
|  | out = (out + (out >> 4)) & 0x0f0f0f0f0f0f0f0fULL; | 
|  |  | 
|  | if (size == 8) {	/* popcntb */ | 
|  | op->val = out; | 
|  | return; | 
|  | } | 
|  | out += out >> 8; | 
|  | out += out >> 16; | 
|  | if (size == 32) {	/* popcntw */ | 
|  | op->val = out & 0x0000003f0000003fULL; | 
|  | return; | 
|  | } | 
|  |  | 
|  | out = (out + (out >> 32)) & 0x7f; | 
|  | op->val = out;	/* popcntd */ | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_PPC64 | 
|  | static nokprobe_inline void do_bpermd(const struct pt_regs *regs, | 
|  | struct instruction_op *op, | 
|  | unsigned long v1, unsigned long v2) | 
|  | { | 
|  | unsigned char perm, idx; | 
|  | unsigned int i; | 
|  |  | 
|  | perm = 0; | 
|  | for (i = 0; i < 8; i++) { | 
|  | idx = (v1 >> (i * 8)) & 0xff; | 
|  | if (idx < 64) | 
|  | if (v2 & PPC_BIT(idx)) | 
|  | perm |= 1 << i; | 
|  | } | 
|  | op->val = perm; | 
|  | } | 
|  | #endif /* CONFIG_PPC64 */ | 
|  | /* | 
|  | * The size parameter adjusts the equivalent prty instruction. | 
|  | * prtyw = 32, prtyd = 64 | 
|  | */ | 
|  | static nokprobe_inline void do_prty(const struct pt_regs *regs, | 
|  | struct instruction_op *op, | 
|  | unsigned long v, int size) | 
|  | { | 
|  | unsigned long long res = v ^ (v >> 8); | 
|  |  | 
|  | res ^= res >> 16; | 
|  | if (size == 32) {		/* prtyw */ | 
|  | op->val = res & 0x0000000100000001ULL; | 
|  | return; | 
|  | } | 
|  |  | 
|  | res ^= res >> 32; | 
|  | op->val = res & 1;	/*prtyd */ | 
|  | } | 
|  |  | 
|  | static nokprobe_inline int trap_compare(long v1, long v2) | 
|  | { | 
|  | int ret = 0; | 
|  |  | 
|  | if (v1 < v2) | 
|  | ret |= 0x10; | 
|  | else if (v1 > v2) | 
|  | ret |= 0x08; | 
|  | else | 
|  | ret |= 0x04; | 
|  | if ((unsigned long)v1 < (unsigned long)v2) | 
|  | ret |= 0x02; | 
|  | else if ((unsigned long)v1 > (unsigned long)v2) | 
|  | ret |= 0x01; | 
|  | return ret; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Elements of 32-bit rotate and mask instructions. | 
|  | */ | 
|  | #define MASK32(mb, me)	((0xffffffffUL >> (mb)) + \ | 
|  | ((signed long)-0x80000000L >> (me)) + ((me) >= (mb))) | 
|  | #ifdef __powerpc64__ | 
|  | #define MASK64_L(mb)	(~0UL >> (mb)) | 
|  | #define MASK64_R(me)	((signed long)-0x8000000000000000L >> (me)) | 
|  | #define MASK64(mb, me)	(MASK64_L(mb) + MASK64_R(me) + ((me) >= (mb))) | 
|  | #define DATA32(x)	(((x) & 0xffffffffUL) | (((x) & 0xffffffffUL) << 32)) | 
|  | #else | 
|  | #define DATA32(x)	(x) | 
|  | #endif | 
|  | #define ROTATE(x, n)	((n) ? (((x) << (n)) | ((x) >> (8 * sizeof(long) - (n)))) : (x)) | 
|  |  | 
|  | /* | 
|  | * Decode an instruction, and return information about it in *op | 
|  | * without changing *regs. | 
|  | * Integer arithmetic and logical instructions, branches, and barrier | 
|  | * instructions can be emulated just using the information in *op. | 
|  | * | 
|  | * Return value is 1 if the instruction can be emulated just by | 
|  | * updating *regs with the information in *op, -1 if we need the | 
|  | * GPRs but *regs doesn't contain the full register set, or 0 | 
|  | * otherwise. | 
|  | */ | 
|  | int analyse_instr(struct instruction_op *op, const struct pt_regs *regs, | 
|  | unsigned int instr) | 
|  | { | 
|  | unsigned int opcode, ra, rb, rd, spr, u; | 
|  | unsigned long int imm; | 
|  | unsigned long int val, val2; | 
|  | unsigned int mb, me, sh; | 
|  | long ival; | 
|  |  | 
|  | op->type = COMPUTE; | 
|  |  | 
|  | opcode = instr >> 26; | 
|  | switch (opcode) { | 
|  | case 16:	/* bc */ | 
|  | op->type = BRANCH; | 
|  | imm = (signed short)(instr & 0xfffc); | 
|  | if ((instr & 2) == 0) | 
|  | imm += regs->nip; | 
|  | op->val = truncate_if_32bit(regs->msr, imm); | 
|  | if (instr & 1) | 
|  | op->type |= SETLK; | 
|  | if (branch_taken(instr, regs, op)) | 
|  | op->type |= BRTAKEN; | 
|  | return 1; | 
|  | #ifdef CONFIG_PPC64 | 
|  | case 17:	/* sc */ | 
|  | if ((instr & 0xfe2) == 2) | 
|  | op->type = SYSCALL; | 
|  | else | 
|  | op->type = UNKNOWN; | 
|  | return 0; | 
|  | #endif | 
|  | case 18:	/* b */ | 
|  | op->type = BRANCH | BRTAKEN; | 
|  | imm = instr & 0x03fffffc; | 
|  | if (imm & 0x02000000) | 
|  | imm -= 0x04000000; | 
|  | if ((instr & 2) == 0) | 
|  | imm += regs->nip; | 
|  | op->val = truncate_if_32bit(regs->msr, imm); | 
|  | if (instr & 1) | 
|  | op->type |= SETLK; | 
|  | return 1; | 
|  | case 19: | 
|  | switch ((instr >> 1) & 0x3ff) { | 
|  | case 0:		/* mcrf */ | 
|  | op->type = COMPUTE + SETCC; | 
|  | rd = 7 - ((instr >> 23) & 0x7); | 
|  | ra = 7 - ((instr >> 18) & 0x7); | 
|  | rd *= 4; | 
|  | ra *= 4; | 
|  | val = (regs->ccr >> ra) & 0xf; | 
|  | op->ccval = (regs->ccr & ~(0xfUL << rd)) | (val << rd); | 
|  | return 1; | 
|  |  | 
|  | case 16:	/* bclr */ | 
|  | case 528:	/* bcctr */ | 
|  | op->type = BRANCH; | 
|  | imm = (instr & 0x400)? regs->ctr: regs->link; | 
|  | op->val = truncate_if_32bit(regs->msr, imm); | 
|  | if (instr & 1) | 
|  | op->type |= SETLK; | 
|  | if (branch_taken(instr, regs, op)) | 
|  | op->type |= BRTAKEN; | 
|  | return 1; | 
|  |  | 
|  | case 18:	/* rfid, scary */ | 
|  | if (regs->msr & MSR_PR) | 
|  | goto priv; | 
|  | op->type = RFI; | 
|  | return 0; | 
|  |  | 
|  | case 150:	/* isync */ | 
|  | op->type = BARRIER | BARRIER_ISYNC; | 
|  | return 1; | 
|  |  | 
|  | case 33:	/* crnor */ | 
|  | case 129:	/* crandc */ | 
|  | case 193:	/* crxor */ | 
|  | case 225:	/* crnand */ | 
|  | case 257:	/* crand */ | 
|  | case 289:	/* creqv */ | 
|  | case 417:	/* crorc */ | 
|  | case 449:	/* cror */ | 
|  | op->type = COMPUTE + SETCC; | 
|  | ra = (instr >> 16) & 0x1f; | 
|  | rb = (instr >> 11) & 0x1f; | 
|  | rd = (instr >> 21) & 0x1f; | 
|  | ra = (regs->ccr >> (31 - ra)) & 1; | 
|  | rb = (regs->ccr >> (31 - rb)) & 1; | 
|  | val = (instr >> (6 + ra * 2 + rb)) & 1; | 
|  | op->ccval = (regs->ccr & ~(1UL << (31 - rd))) | | 
|  | (val << (31 - rd)); | 
|  | return 1; | 
|  | } | 
|  | break; | 
|  | case 31: | 
|  | switch ((instr >> 1) & 0x3ff) { | 
|  | case 598:	/* sync */ | 
|  | op->type = BARRIER + BARRIER_SYNC; | 
|  | #ifdef __powerpc64__ | 
|  | switch ((instr >> 21) & 3) { | 
|  | case 1:		/* lwsync */ | 
|  | op->type = BARRIER + BARRIER_LWSYNC; | 
|  | break; | 
|  | case 2:		/* ptesync */ | 
|  | op->type = BARRIER + BARRIER_PTESYNC; | 
|  | break; | 
|  | } | 
|  | #endif | 
|  | return 1; | 
|  |  | 
|  | case 854:	/* eieio */ | 
|  | op->type = BARRIER + BARRIER_EIEIO; | 
|  | return 1; | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* Following cases refer to regs->gpr[], so we need all regs */ | 
|  | if (!FULL_REGS(regs)) | 
|  | return -1; | 
|  |  | 
|  | rd = (instr >> 21) & 0x1f; | 
|  | ra = (instr >> 16) & 0x1f; | 
|  | rb = (instr >> 11) & 0x1f; | 
|  |  | 
|  | switch (opcode) { | 
|  | #ifdef __powerpc64__ | 
|  | case 2:		/* tdi */ | 
|  | if (rd & trap_compare(regs->gpr[ra], (short) instr)) | 
|  | goto trap; | 
|  | return 1; | 
|  | #endif | 
|  | case 3:		/* twi */ | 
|  | if (rd & trap_compare((int)regs->gpr[ra], (short) instr)) | 
|  | goto trap; | 
|  | return 1; | 
|  |  | 
|  | case 7:		/* mulli */ | 
|  | op->val = regs->gpr[ra] * (short) instr; | 
|  | goto compute_done; | 
|  |  | 
|  | case 8:		/* subfic */ | 
|  | imm = (short) instr; | 
|  | add_with_carry(regs, op, rd, ~regs->gpr[ra], imm, 1); | 
|  | return 1; | 
|  |  | 
|  | case 10:	/* cmpli */ | 
|  | imm = (unsigned short) instr; | 
|  | val = regs->gpr[ra]; | 
|  | #ifdef __powerpc64__ | 
|  | if ((rd & 1) == 0) | 
|  | val = (unsigned int) val; | 
|  | #endif | 
|  | do_cmp_unsigned(regs, op, val, imm, rd >> 2); | 
|  | return 1; | 
|  |  | 
|  | case 11:	/* cmpi */ | 
|  | imm = (short) instr; | 
|  | val = regs->gpr[ra]; | 
|  | #ifdef __powerpc64__ | 
|  | if ((rd & 1) == 0) | 
|  | val = (int) val; | 
|  | #endif | 
|  | do_cmp_signed(regs, op, val, imm, rd >> 2); | 
|  | return 1; | 
|  |  | 
|  | case 12:	/* addic */ | 
|  | imm = (short) instr; | 
|  | add_with_carry(regs, op, rd, regs->gpr[ra], imm, 0); | 
|  | return 1; | 
|  |  | 
|  | case 13:	/* addic. */ | 
|  | imm = (short) instr; | 
|  | add_with_carry(regs, op, rd, regs->gpr[ra], imm, 0); | 
|  | set_cr0(regs, op); | 
|  | return 1; | 
|  |  | 
|  | case 14:	/* addi */ | 
|  | imm = (short) instr; | 
|  | if (ra) | 
|  | imm += regs->gpr[ra]; | 
|  | op->val = imm; | 
|  | goto compute_done; | 
|  |  | 
|  | case 15:	/* addis */ | 
|  | imm = ((short) instr) << 16; | 
|  | if (ra) | 
|  | imm += regs->gpr[ra]; | 
|  | op->val = imm; | 
|  | goto compute_done; | 
|  |  | 
|  | case 19: | 
|  | if (((instr >> 1) & 0x1f) == 2) { | 
|  | /* addpcis */ | 
|  | imm = (short) (instr & 0xffc1);	/* d0 + d2 fields */ | 
|  | imm |= (instr >> 15) & 0x3e;	/* d1 field */ | 
|  | op->val = regs->nip + (imm << 16) + 4; | 
|  | goto compute_done; | 
|  | } | 
|  | op->type = UNKNOWN; | 
|  | return 0; | 
|  |  | 
|  | case 20:	/* rlwimi */ | 
|  | mb = (instr >> 6) & 0x1f; | 
|  | me = (instr >> 1) & 0x1f; | 
|  | val = DATA32(regs->gpr[rd]); | 
|  | imm = MASK32(mb, me); | 
|  | op->val = (regs->gpr[ra] & ~imm) | (ROTATE(val, rb) & imm); | 
|  | goto logical_done; | 
|  |  | 
|  | case 21:	/* rlwinm */ | 
|  | mb = (instr >> 6) & 0x1f; | 
|  | me = (instr >> 1) & 0x1f; | 
|  | val = DATA32(regs->gpr[rd]); | 
|  | op->val = ROTATE(val, rb) & MASK32(mb, me); | 
|  | goto logical_done; | 
|  |  | 
|  | case 23:	/* rlwnm */ | 
|  | mb = (instr >> 6) & 0x1f; | 
|  | me = (instr >> 1) & 0x1f; | 
|  | rb = regs->gpr[rb] & 0x1f; | 
|  | val = DATA32(regs->gpr[rd]); | 
|  | op->val = ROTATE(val, rb) & MASK32(mb, me); | 
|  | goto logical_done; | 
|  |  | 
|  | case 24:	/* ori */ | 
|  | op->val = regs->gpr[rd] | (unsigned short) instr; | 
|  | goto logical_done_nocc; | 
|  |  | 
|  | case 25:	/* oris */ | 
|  | imm = (unsigned short) instr; | 
|  | op->val = regs->gpr[rd] | (imm << 16); | 
|  | goto logical_done_nocc; | 
|  |  | 
|  | case 26:	/* xori */ | 
|  | op->val = regs->gpr[rd] ^ (unsigned short) instr; | 
|  | goto logical_done_nocc; | 
|  |  | 
|  | case 27:	/* xoris */ | 
|  | imm = (unsigned short) instr; | 
|  | op->val = regs->gpr[rd] ^ (imm << 16); | 
|  | goto logical_done_nocc; | 
|  |  | 
|  | case 28:	/* andi. */ | 
|  | op->val = regs->gpr[rd] & (unsigned short) instr; | 
|  | set_cr0(regs, op); | 
|  | goto logical_done_nocc; | 
|  |  | 
|  | case 29:	/* andis. */ | 
|  | imm = (unsigned short) instr; | 
|  | op->val = regs->gpr[rd] & (imm << 16); | 
|  | set_cr0(regs, op); | 
|  | goto logical_done_nocc; | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 30:	/* rld* */ | 
|  | mb = ((instr >> 6) & 0x1f) | (instr & 0x20); | 
|  | val = regs->gpr[rd]; | 
|  | if ((instr & 0x10) == 0) { | 
|  | sh = rb | ((instr & 2) << 4); | 
|  | val = ROTATE(val, sh); | 
|  | switch ((instr >> 2) & 3) { | 
|  | case 0:		/* rldicl */ | 
|  | val &= MASK64_L(mb); | 
|  | break; | 
|  | case 1:		/* rldicr */ | 
|  | val &= MASK64_R(mb); | 
|  | break; | 
|  | case 2:		/* rldic */ | 
|  | val &= MASK64(mb, 63 - sh); | 
|  | break; | 
|  | case 3:		/* rldimi */ | 
|  | imm = MASK64(mb, 63 - sh); | 
|  | val = (regs->gpr[ra] & ~imm) | | 
|  | (val & imm); | 
|  | } | 
|  | op->val = val; | 
|  | goto logical_done; | 
|  | } else { | 
|  | sh = regs->gpr[rb] & 0x3f; | 
|  | val = ROTATE(val, sh); | 
|  | switch ((instr >> 1) & 7) { | 
|  | case 0:		/* rldcl */ | 
|  | op->val = val & MASK64_L(mb); | 
|  | goto logical_done; | 
|  | case 1:		/* rldcr */ | 
|  | op->val = val & MASK64_R(mb); | 
|  | goto logical_done; | 
|  | } | 
|  | } | 
|  | #endif | 
|  | op->type = UNKNOWN;	/* illegal instruction */ | 
|  | return 0; | 
|  |  | 
|  | case 31: | 
|  | /* isel occupies 32 minor opcodes */ | 
|  | if (((instr >> 1) & 0x1f) == 15) { | 
|  | mb = (instr >> 6) & 0x1f; /* bc field */ | 
|  | val = (regs->ccr >> (31 - mb)) & 1; | 
|  | val2 = (ra) ? regs->gpr[ra] : 0; | 
|  |  | 
|  | op->val = (val) ? val2 : regs->gpr[rb]; | 
|  | goto compute_done; | 
|  | } | 
|  |  | 
|  | switch ((instr >> 1) & 0x3ff) { | 
|  | case 4:		/* tw */ | 
|  | if (rd == 0x1f || | 
|  | (rd & trap_compare((int)regs->gpr[ra], | 
|  | (int)regs->gpr[rb]))) | 
|  | goto trap; | 
|  | return 1; | 
|  | #ifdef __powerpc64__ | 
|  | case 68:	/* td */ | 
|  | if (rd & trap_compare(regs->gpr[ra], regs->gpr[rb])) | 
|  | goto trap; | 
|  | return 1; | 
|  | #endif | 
|  | case 83:	/* mfmsr */ | 
|  | if (regs->msr & MSR_PR) | 
|  | goto priv; | 
|  | op->type = MFMSR; | 
|  | op->reg = rd; | 
|  | return 0; | 
|  | case 146:	/* mtmsr */ | 
|  | if (regs->msr & MSR_PR) | 
|  | goto priv; | 
|  | op->type = MTMSR; | 
|  | op->reg = rd; | 
|  | op->val = 0xffffffff & ~(MSR_ME | MSR_LE); | 
|  | return 0; | 
|  | #ifdef CONFIG_PPC64 | 
|  | case 178:	/* mtmsrd */ | 
|  | if (regs->msr & MSR_PR) | 
|  | goto priv; | 
|  | op->type = MTMSR; | 
|  | op->reg = rd; | 
|  | /* only MSR_EE and MSR_RI get changed if bit 15 set */ | 
|  | /* mtmsrd doesn't change MSR_HV, MSR_ME or MSR_LE */ | 
|  | imm = (instr & 0x10000)? 0x8002: 0xefffffffffffeffeUL; | 
|  | op->val = imm; | 
|  | return 0; | 
|  | #endif | 
|  |  | 
|  | case 19:	/* mfcr */ | 
|  | imm = 0xffffffffUL; | 
|  | if ((instr >> 20) & 1) { | 
|  | imm = 0xf0000000UL; | 
|  | for (sh = 0; sh < 8; ++sh) { | 
|  | if (instr & (0x80000 >> sh)) | 
|  | break; | 
|  | imm >>= 4; | 
|  | } | 
|  | } | 
|  | op->val = regs->ccr & imm; | 
|  | goto compute_done; | 
|  |  | 
|  | case 144:	/* mtcrf */ | 
|  | op->type = COMPUTE + SETCC; | 
|  | imm = 0xf0000000UL; | 
|  | val = regs->gpr[rd]; | 
|  | op->ccval = regs->ccr; | 
|  | for (sh = 0; sh < 8; ++sh) { | 
|  | if (instr & (0x80000 >> sh)) | 
|  | op->ccval = (op->ccval & ~imm) | | 
|  | (val & imm); | 
|  | imm >>= 4; | 
|  | } | 
|  | return 1; | 
|  |  | 
|  | case 339:	/* mfspr */ | 
|  | spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0); | 
|  | op->type = MFSPR; | 
|  | op->reg = rd; | 
|  | op->spr = spr; | 
|  | if (spr == SPRN_XER || spr == SPRN_LR || | 
|  | spr == SPRN_CTR) | 
|  | return 1; | 
|  | return 0; | 
|  |  | 
|  | case 467:	/* mtspr */ | 
|  | spr = ((instr >> 16) & 0x1f) | ((instr >> 6) & 0x3e0); | 
|  | op->type = MTSPR; | 
|  | op->val = regs->gpr[rd]; | 
|  | op->spr = spr; | 
|  | if (spr == SPRN_XER || spr == SPRN_LR || | 
|  | spr == SPRN_CTR) | 
|  | return 1; | 
|  | return 0; | 
|  |  | 
|  | /* | 
|  | * Compare instructions | 
|  | */ | 
|  | case 0:	/* cmp */ | 
|  | val = regs->gpr[ra]; | 
|  | val2 = regs->gpr[rb]; | 
|  | #ifdef __powerpc64__ | 
|  | if ((rd & 1) == 0) { | 
|  | /* word (32-bit) compare */ | 
|  | val = (int) val; | 
|  | val2 = (int) val2; | 
|  | } | 
|  | #endif | 
|  | do_cmp_signed(regs, op, val, val2, rd >> 2); | 
|  | return 1; | 
|  |  | 
|  | case 32:	/* cmpl */ | 
|  | val = regs->gpr[ra]; | 
|  | val2 = regs->gpr[rb]; | 
|  | #ifdef __powerpc64__ | 
|  | if ((rd & 1) == 0) { | 
|  | /* word (32-bit) compare */ | 
|  | val = (unsigned int) val; | 
|  | val2 = (unsigned int) val2; | 
|  | } | 
|  | #endif | 
|  | do_cmp_unsigned(regs, op, val, val2, rd >> 2); | 
|  | return 1; | 
|  |  | 
|  | case 508: /* cmpb */ | 
|  | do_cmpb(regs, op, regs->gpr[rd], regs->gpr[rb]); | 
|  | goto logical_done_nocc; | 
|  |  | 
|  | /* | 
|  | * Arithmetic instructions | 
|  | */ | 
|  | case 8:	/* subfc */ | 
|  | add_with_carry(regs, op, rd, ~regs->gpr[ra], | 
|  | regs->gpr[rb], 1); | 
|  | goto arith_done; | 
|  | #ifdef __powerpc64__ | 
|  | case 9:	/* mulhdu */ | 
|  | asm("mulhdu %0,%1,%2" : "=r" (op->val) : | 
|  | "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); | 
|  | goto arith_done; | 
|  | #endif | 
|  | case 10:	/* addc */ | 
|  | add_with_carry(regs, op, rd, regs->gpr[ra], | 
|  | regs->gpr[rb], 0); | 
|  | goto arith_done; | 
|  |  | 
|  | case 11:	/* mulhwu */ | 
|  | asm("mulhwu %0,%1,%2" : "=r" (op->val) : | 
|  | "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); | 
|  | goto arith_done; | 
|  |  | 
|  | case 40:	/* subf */ | 
|  | op->val = regs->gpr[rb] - regs->gpr[ra]; | 
|  | goto arith_done; | 
|  | #ifdef __powerpc64__ | 
|  | case 73:	/* mulhd */ | 
|  | asm("mulhd %0,%1,%2" : "=r" (op->val) : | 
|  | "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); | 
|  | goto arith_done; | 
|  | #endif | 
|  | case 75:	/* mulhw */ | 
|  | asm("mulhw %0,%1,%2" : "=r" (op->val) : | 
|  | "r" (regs->gpr[ra]), "r" (regs->gpr[rb])); | 
|  | goto arith_done; | 
|  |  | 
|  | case 104:	/* neg */ | 
|  | op->val = -regs->gpr[ra]; | 
|  | goto arith_done; | 
|  |  | 
|  | case 136:	/* subfe */ | 
|  | add_with_carry(regs, op, rd, ~regs->gpr[ra], | 
|  | regs->gpr[rb], regs->xer & XER_CA); | 
|  | goto arith_done; | 
|  |  | 
|  | case 138:	/* adde */ | 
|  | add_with_carry(regs, op, rd, regs->gpr[ra], | 
|  | regs->gpr[rb], regs->xer & XER_CA); | 
|  | goto arith_done; | 
|  |  | 
|  | case 200:	/* subfze */ | 
|  | add_with_carry(regs, op, rd, ~regs->gpr[ra], 0L, | 
|  | regs->xer & XER_CA); | 
|  | goto arith_done; | 
|  |  | 
|  | case 202:	/* addze */ | 
|  | add_with_carry(regs, op, rd, regs->gpr[ra], 0L, | 
|  | regs->xer & XER_CA); | 
|  | goto arith_done; | 
|  |  | 
|  | case 232:	/* subfme */ | 
|  | add_with_carry(regs, op, rd, ~regs->gpr[ra], -1L, | 
|  | regs->xer & XER_CA); | 
|  | goto arith_done; | 
|  | #ifdef __powerpc64__ | 
|  | case 233:	/* mulld */ | 
|  | op->val = regs->gpr[ra] * regs->gpr[rb]; | 
|  | goto arith_done; | 
|  | #endif | 
|  | case 234:	/* addme */ | 
|  | add_with_carry(regs, op, rd, regs->gpr[ra], -1L, | 
|  | regs->xer & XER_CA); | 
|  | goto arith_done; | 
|  |  | 
|  | case 235:	/* mullw */ | 
|  | op->val = (long)(int) regs->gpr[ra] * | 
|  | (int) regs->gpr[rb]; | 
|  |  | 
|  | goto arith_done; | 
|  |  | 
|  | case 266:	/* add */ | 
|  | op->val = regs->gpr[ra] + regs->gpr[rb]; | 
|  | goto arith_done; | 
|  | #ifdef __powerpc64__ | 
|  | case 457:	/* divdu */ | 
|  | op->val = regs->gpr[ra] / regs->gpr[rb]; | 
|  | goto arith_done; | 
|  | #endif | 
|  | case 459:	/* divwu */ | 
|  | op->val = (unsigned int) regs->gpr[ra] / | 
|  | (unsigned int) regs->gpr[rb]; | 
|  | goto arith_done; | 
|  | #ifdef __powerpc64__ | 
|  | case 489:	/* divd */ | 
|  | op->val = (long int) regs->gpr[ra] / | 
|  | (long int) regs->gpr[rb]; | 
|  | goto arith_done; | 
|  | #endif | 
|  | case 491:	/* divw */ | 
|  | op->val = (int) regs->gpr[ra] / | 
|  | (int) regs->gpr[rb]; | 
|  | goto arith_done; | 
|  |  | 
|  |  | 
|  | /* | 
|  | * Logical instructions | 
|  | */ | 
|  | case 26:	/* cntlzw */ | 
|  | val = (unsigned int) regs->gpr[rd]; | 
|  | op->val = ( val ? __builtin_clz(val) : 32 ); | 
|  | goto logical_done; | 
|  | #ifdef __powerpc64__ | 
|  | case 58:	/* cntlzd */ | 
|  | val = regs->gpr[rd]; | 
|  | op->val = ( val ? __builtin_clzl(val) : 64 ); | 
|  | goto logical_done; | 
|  | #endif | 
|  | case 28:	/* and */ | 
|  | op->val = regs->gpr[rd] & regs->gpr[rb]; | 
|  | goto logical_done; | 
|  |  | 
|  | case 60:	/* andc */ | 
|  | op->val = regs->gpr[rd] & ~regs->gpr[rb]; | 
|  | goto logical_done; | 
|  |  | 
|  | case 122:	/* popcntb */ | 
|  | do_popcnt(regs, op, regs->gpr[rd], 8); | 
|  | goto logical_done_nocc; | 
|  |  | 
|  | case 124:	/* nor */ | 
|  | op->val = ~(regs->gpr[rd] | regs->gpr[rb]); | 
|  | goto logical_done; | 
|  |  | 
|  | case 154:	/* prtyw */ | 
|  | do_prty(regs, op, regs->gpr[rd], 32); | 
|  | goto logical_done_nocc; | 
|  |  | 
|  | case 186:	/* prtyd */ | 
|  | do_prty(regs, op, regs->gpr[rd], 64); | 
|  | goto logical_done_nocc; | 
|  | #ifdef CONFIG_PPC64 | 
|  | case 252:	/* bpermd */ | 
|  | do_bpermd(regs, op, regs->gpr[rd], regs->gpr[rb]); | 
|  | goto logical_done_nocc; | 
|  | #endif | 
|  | case 284:	/* xor */ | 
|  | op->val = ~(regs->gpr[rd] ^ regs->gpr[rb]); | 
|  | goto logical_done; | 
|  |  | 
|  | case 316:	/* xor */ | 
|  | op->val = regs->gpr[rd] ^ regs->gpr[rb]; | 
|  | goto logical_done; | 
|  |  | 
|  | case 378:	/* popcntw */ | 
|  | do_popcnt(regs, op, regs->gpr[rd], 32); | 
|  | goto logical_done_nocc; | 
|  |  | 
|  | case 412:	/* orc */ | 
|  | op->val = regs->gpr[rd] | ~regs->gpr[rb]; | 
|  | goto logical_done; | 
|  |  | 
|  | case 444:	/* or */ | 
|  | op->val = regs->gpr[rd] | regs->gpr[rb]; | 
|  | goto logical_done; | 
|  |  | 
|  | case 476:	/* nand */ | 
|  | op->val = ~(regs->gpr[rd] & regs->gpr[rb]); | 
|  | goto logical_done; | 
|  | #ifdef CONFIG_PPC64 | 
|  | case 506:	/* popcntd */ | 
|  | do_popcnt(regs, op, regs->gpr[rd], 64); | 
|  | goto logical_done_nocc; | 
|  | #endif | 
|  | case 922:	/* extsh */ | 
|  | op->val = (signed short) regs->gpr[rd]; | 
|  | goto logical_done; | 
|  |  | 
|  | case 954:	/* extsb */ | 
|  | op->val = (signed char) regs->gpr[rd]; | 
|  | goto logical_done; | 
|  | #ifdef __powerpc64__ | 
|  | case 986:	/* extsw */ | 
|  | op->val = (signed int) regs->gpr[rd]; | 
|  | goto logical_done; | 
|  | #endif | 
|  |  | 
|  | /* | 
|  | * Shift instructions | 
|  | */ | 
|  | case 24:	/* slw */ | 
|  | sh = regs->gpr[rb] & 0x3f; | 
|  | if (sh < 32) | 
|  | op->val = (regs->gpr[rd] << sh) & 0xffffffffUL; | 
|  | else | 
|  | op->val = 0; | 
|  | goto logical_done; | 
|  |  | 
|  | case 536:	/* srw */ | 
|  | sh = regs->gpr[rb] & 0x3f; | 
|  | if (sh < 32) | 
|  | op->val = (regs->gpr[rd] & 0xffffffffUL) >> sh; | 
|  | else | 
|  | op->val = 0; | 
|  | goto logical_done; | 
|  |  | 
|  | case 792:	/* sraw */ | 
|  | op->type = COMPUTE + SETREG + SETXER; | 
|  | sh = regs->gpr[rb] & 0x3f; | 
|  | ival = (signed int) regs->gpr[rd]; | 
|  | op->val = ival >> (sh < 32 ? sh : 31); | 
|  | op->xerval = regs->xer; | 
|  | if (ival < 0 && (sh >= 32 || (ival & ((1ul << sh) - 1)) != 0)) | 
|  | op->xerval |= XER_CA; | 
|  | else | 
|  | op->xerval &= ~XER_CA; | 
|  | set_ca32(op, op->xerval & XER_CA); | 
|  | goto logical_done; | 
|  |  | 
|  | case 824:	/* srawi */ | 
|  | op->type = COMPUTE + SETREG + SETXER; | 
|  | sh = rb; | 
|  | ival = (signed int) regs->gpr[rd]; | 
|  | op->val = ival >> sh; | 
|  | op->xerval = regs->xer; | 
|  | if (ival < 0 && (ival & ((1ul << sh) - 1)) != 0) | 
|  | op->xerval |= XER_CA; | 
|  | else | 
|  | op->xerval &= ~XER_CA; | 
|  | set_ca32(op, op->xerval & XER_CA); | 
|  | goto logical_done; | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 27:	/* sld */ | 
|  | sh = regs->gpr[rb] & 0x7f; | 
|  | if (sh < 64) | 
|  | op->val = regs->gpr[rd] << sh; | 
|  | else | 
|  | op->val = 0; | 
|  | goto logical_done; | 
|  |  | 
|  | case 539:	/* srd */ | 
|  | sh = regs->gpr[rb] & 0x7f; | 
|  | if (sh < 64) | 
|  | op->val = regs->gpr[rd] >> sh; | 
|  | else | 
|  | op->val = 0; | 
|  | goto logical_done; | 
|  |  | 
|  | case 794:	/* srad */ | 
|  | op->type = COMPUTE + SETREG + SETXER; | 
|  | sh = regs->gpr[rb] & 0x7f; | 
|  | ival = (signed long int) regs->gpr[rd]; | 
|  | op->val = ival >> (sh < 64 ? sh : 63); | 
|  | op->xerval = regs->xer; | 
|  | if (ival < 0 && (sh >= 64 || (ival & ((1ul << sh) - 1)) != 0)) | 
|  | op->xerval |= XER_CA; | 
|  | else | 
|  | op->xerval &= ~XER_CA; | 
|  | set_ca32(op, op->xerval & XER_CA); | 
|  | goto logical_done; | 
|  |  | 
|  | case 826:	/* sradi with sh_5 = 0 */ | 
|  | case 827:	/* sradi with sh_5 = 1 */ | 
|  | op->type = COMPUTE + SETREG + SETXER; | 
|  | sh = rb | ((instr & 2) << 4); | 
|  | ival = (signed long int) regs->gpr[rd]; | 
|  | op->val = ival >> sh; | 
|  | op->xerval = regs->xer; | 
|  | if (ival < 0 && (ival & ((1ul << sh) - 1)) != 0) | 
|  | op->xerval |= XER_CA; | 
|  | else | 
|  | op->xerval &= ~XER_CA; | 
|  | set_ca32(op, op->xerval & XER_CA); | 
|  | goto logical_done; | 
|  | #endif /* __powerpc64__ */ | 
|  |  | 
|  | /* | 
|  | * Cache instructions | 
|  | */ | 
|  | case 54:	/* dcbst */ | 
|  | op->type = MKOP(CACHEOP, DCBST, 0); | 
|  | op->ea = xform_ea(instr, regs); | 
|  | return 0; | 
|  |  | 
|  | case 86:	/* dcbf */ | 
|  | op->type = MKOP(CACHEOP, DCBF, 0); | 
|  | op->ea = xform_ea(instr, regs); | 
|  | return 0; | 
|  |  | 
|  | case 246:	/* dcbtst */ | 
|  | op->type = MKOP(CACHEOP, DCBTST, 0); | 
|  | op->ea = xform_ea(instr, regs); | 
|  | op->reg = rd; | 
|  | return 0; | 
|  |  | 
|  | case 278:	/* dcbt */ | 
|  | op->type = MKOP(CACHEOP, DCBTST, 0); | 
|  | op->ea = xform_ea(instr, regs); | 
|  | op->reg = rd; | 
|  | return 0; | 
|  |  | 
|  | case 982:	/* icbi */ | 
|  | op->type = MKOP(CACHEOP, ICBI, 0); | 
|  | op->ea = xform_ea(instr, regs); | 
|  | return 0; | 
|  |  | 
|  | case 1014:	/* dcbz */ | 
|  | op->type = MKOP(CACHEOP, DCBZ, 0); | 
|  | op->ea = xform_ea(instr, regs); | 
|  | return 0; | 
|  | } | 
|  | break; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Loads and stores. | 
|  | */ | 
|  | op->type = UNKNOWN; | 
|  | op->update_reg = ra; | 
|  | op->reg = rd; | 
|  | op->val = regs->gpr[rd]; | 
|  | u = (instr >> 20) & UPDATE; | 
|  | op->vsx_flags = 0; | 
|  |  | 
|  | switch (opcode) { | 
|  | case 31: | 
|  | u = instr & UPDATE; | 
|  | op->ea = xform_ea(instr, regs); | 
|  | switch ((instr >> 1) & 0x3ff) { | 
|  | case 20:	/* lwarx */ | 
|  | op->type = MKOP(LARX, 0, 4); | 
|  | break; | 
|  |  | 
|  | case 150:	/* stwcx. */ | 
|  | op->type = MKOP(STCX, 0, 4); | 
|  | break; | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 84:	/* ldarx */ | 
|  | op->type = MKOP(LARX, 0, 8); | 
|  | break; | 
|  |  | 
|  | case 214:	/* stdcx. */ | 
|  | op->type = MKOP(STCX, 0, 8); | 
|  | break; | 
|  |  | 
|  | case 52:	/* lbarx */ | 
|  | op->type = MKOP(LARX, 0, 1); | 
|  | break; | 
|  |  | 
|  | case 694:	/* stbcx. */ | 
|  | op->type = MKOP(STCX, 0, 1); | 
|  | break; | 
|  |  | 
|  | case 116:	/* lharx */ | 
|  | op->type = MKOP(LARX, 0, 2); | 
|  | break; | 
|  |  | 
|  | case 726:	/* sthcx. */ | 
|  | op->type = MKOP(STCX, 0, 2); | 
|  | break; | 
|  |  | 
|  | case 276:	/* lqarx */ | 
|  | if (!((rd & 1) || rd == ra || rd == rb)) | 
|  | op->type = MKOP(LARX, 0, 16); | 
|  | break; | 
|  |  | 
|  | case 182:	/* stqcx. */ | 
|  | if (!(rd & 1)) | 
|  | op->type = MKOP(STCX, 0, 16); | 
|  | break; | 
|  | #endif | 
|  |  | 
|  | case 23:	/* lwzx */ | 
|  | case 55:	/* lwzux */ | 
|  | op->type = MKOP(LOAD, u, 4); | 
|  | break; | 
|  |  | 
|  | case 87:	/* lbzx */ | 
|  | case 119:	/* lbzux */ | 
|  | op->type = MKOP(LOAD, u, 1); | 
|  | break; | 
|  |  | 
|  | #ifdef CONFIG_ALTIVEC | 
|  | /* | 
|  | * Note: for the load/store vector element instructions, | 
|  | * bits of the EA say which field of the VMX register to use. | 
|  | */ | 
|  | case 7:		/* lvebx */ | 
|  | op->type = MKOP(LOAD_VMX, 0, 1); | 
|  | op->element_size = 1; | 
|  | break; | 
|  |  | 
|  | case 39:	/* lvehx */ | 
|  | op->type = MKOP(LOAD_VMX, 0, 2); | 
|  | op->element_size = 2; | 
|  | break; | 
|  |  | 
|  | case 71:	/* lvewx */ | 
|  | op->type = MKOP(LOAD_VMX, 0, 4); | 
|  | op->element_size = 4; | 
|  | break; | 
|  |  | 
|  | case 103:	/* lvx */ | 
|  | case 359:	/* lvxl */ | 
|  | op->type = MKOP(LOAD_VMX, 0, 16); | 
|  | op->element_size = 16; | 
|  | break; | 
|  |  | 
|  | case 135:	/* stvebx */ | 
|  | op->type = MKOP(STORE_VMX, 0, 1); | 
|  | op->element_size = 1; | 
|  | break; | 
|  |  | 
|  | case 167:	/* stvehx */ | 
|  | op->type = MKOP(STORE_VMX, 0, 2); | 
|  | op->element_size = 2; | 
|  | break; | 
|  |  | 
|  | case 199:	/* stvewx */ | 
|  | op->type = MKOP(STORE_VMX, 0, 4); | 
|  | op->element_size = 4; | 
|  | break; | 
|  |  | 
|  | case 231:	/* stvx */ | 
|  | case 487:	/* stvxl */ | 
|  | op->type = MKOP(STORE_VMX, 0, 16); | 
|  | break; | 
|  | #endif /* CONFIG_ALTIVEC */ | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 21:	/* ldx */ | 
|  | case 53:	/* ldux */ | 
|  | op->type = MKOP(LOAD, u, 8); | 
|  | break; | 
|  |  | 
|  | case 149:	/* stdx */ | 
|  | case 181:	/* stdux */ | 
|  | op->type = MKOP(STORE, u, 8); | 
|  | break; | 
|  | #endif | 
|  |  | 
|  | case 151:	/* stwx */ | 
|  | case 183:	/* stwux */ | 
|  | op->type = MKOP(STORE, u, 4); | 
|  | break; | 
|  |  | 
|  | case 215:	/* stbx */ | 
|  | case 247:	/* stbux */ | 
|  | op->type = MKOP(STORE, u, 1); | 
|  | break; | 
|  |  | 
|  | case 279:	/* lhzx */ | 
|  | case 311:	/* lhzux */ | 
|  | op->type = MKOP(LOAD, u, 2); | 
|  | break; | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 341:	/* lwax */ | 
|  | case 373:	/* lwaux */ | 
|  | op->type = MKOP(LOAD, SIGNEXT | u, 4); | 
|  | break; | 
|  | #endif | 
|  |  | 
|  | case 343:	/* lhax */ | 
|  | case 375:	/* lhaux */ | 
|  | op->type = MKOP(LOAD, SIGNEXT | u, 2); | 
|  | break; | 
|  |  | 
|  | case 407:	/* sthx */ | 
|  | case 439:	/* sthux */ | 
|  | op->type = MKOP(STORE, u, 2); | 
|  | break; | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 532:	/* ldbrx */ | 
|  | op->type = MKOP(LOAD, BYTEREV, 8); | 
|  | break; | 
|  |  | 
|  | #endif | 
|  | case 533:	/* lswx */ | 
|  | op->type = MKOP(LOAD_MULTI, 0, regs->xer & 0x7f); | 
|  | break; | 
|  |  | 
|  | case 534:	/* lwbrx */ | 
|  | op->type = MKOP(LOAD, BYTEREV, 4); | 
|  | break; | 
|  |  | 
|  | case 597:	/* lswi */ | 
|  | if (rb == 0) | 
|  | rb = 32;	/* # bytes to load */ | 
|  | op->type = MKOP(LOAD_MULTI, 0, rb); | 
|  | op->ea = ra ? regs->gpr[ra] : 0; | 
|  | break; | 
|  |  | 
|  | #ifdef CONFIG_PPC_FPU | 
|  | case 535:	/* lfsx */ | 
|  | case 567:	/* lfsux */ | 
|  | op->type = MKOP(LOAD_FP, u | FPCONV, 4); | 
|  | break; | 
|  |  | 
|  | case 599:	/* lfdx */ | 
|  | case 631:	/* lfdux */ | 
|  | op->type = MKOP(LOAD_FP, u, 8); | 
|  | break; | 
|  |  | 
|  | case 663:	/* stfsx */ | 
|  | case 695:	/* stfsux */ | 
|  | op->type = MKOP(STORE_FP, u | FPCONV, 4); | 
|  | break; | 
|  |  | 
|  | case 727:	/* stfdx */ | 
|  | case 759:	/* stfdux */ | 
|  | op->type = MKOP(STORE_FP, u, 8); | 
|  | break; | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 791:	/* lfdpx */ | 
|  | op->type = MKOP(LOAD_FP, 0, 16); | 
|  | break; | 
|  |  | 
|  | case 855:	/* lfiwax */ | 
|  | op->type = MKOP(LOAD_FP, SIGNEXT, 4); | 
|  | break; | 
|  |  | 
|  | case 887:	/* lfiwzx */ | 
|  | op->type = MKOP(LOAD_FP, 0, 4); | 
|  | break; | 
|  |  | 
|  | case 919:	/* stfdpx */ | 
|  | op->type = MKOP(STORE_FP, 0, 16); | 
|  | break; | 
|  |  | 
|  | case 983:	/* stfiwx */ | 
|  | op->type = MKOP(STORE_FP, 0, 4); | 
|  | break; | 
|  | #endif /* __powerpc64 */ | 
|  | #endif /* CONFIG_PPC_FPU */ | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 660:	/* stdbrx */ | 
|  | op->type = MKOP(STORE, BYTEREV, 8); | 
|  | op->val = byterev_8(regs->gpr[rd]); | 
|  | break; | 
|  |  | 
|  | #endif | 
|  | case 661:	/* stswx */ | 
|  | op->type = MKOP(STORE_MULTI, 0, regs->xer & 0x7f); | 
|  | break; | 
|  |  | 
|  | case 662:	/* stwbrx */ | 
|  | op->type = MKOP(STORE, BYTEREV, 4); | 
|  | op->val = byterev_4(regs->gpr[rd]); | 
|  | break; | 
|  |  | 
|  | case 725:	/* stswi */ | 
|  | if (rb == 0) | 
|  | rb = 32;	/* # bytes to store */ | 
|  | op->type = MKOP(STORE_MULTI, 0, rb); | 
|  | op->ea = ra ? regs->gpr[ra] : 0; | 
|  | break; | 
|  |  | 
|  | case 790:	/* lhbrx */ | 
|  | op->type = MKOP(LOAD, BYTEREV, 2); | 
|  | break; | 
|  |  | 
|  | case 918:	/* sthbrx */ | 
|  | op->type = MKOP(STORE, BYTEREV, 2); | 
|  | op->val = byterev_2(regs->gpr[rd]); | 
|  | break; | 
|  |  | 
|  | #ifdef CONFIG_VSX | 
|  | case 12:	/* lxsiwzx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 4); | 
|  | op->element_size = 8; | 
|  | break; | 
|  |  | 
|  | case 76:	/* lxsiwax */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, SIGNEXT, 4); | 
|  | op->element_size = 8; | 
|  | break; | 
|  |  | 
|  | case 140:	/* stxsiwx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(STORE_VSX, 0, 4); | 
|  | op->element_size = 8; | 
|  | break; | 
|  |  | 
|  | case 268:	/* lxvx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 16); | 
|  | op->element_size = 16; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 269:	/* lxvl */ | 
|  | case 301: {	/* lxvll */ | 
|  | int nb; | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->ea = ra ? regs->gpr[ra] : 0; | 
|  | nb = regs->gpr[rb] & 0xff; | 
|  | if (nb > 16) | 
|  | nb = 16; | 
|  | op->type = MKOP(LOAD_VSX, 0, nb); | 
|  | op->element_size = 16; | 
|  | op->vsx_flags = ((instr & 0x20) ? VSX_LDLEFT : 0) | | 
|  | VSX_CHECK_VEC; | 
|  | break; | 
|  | } | 
|  | case 332:	/* lxvdsx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 8); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_SPLAT; | 
|  | break; | 
|  |  | 
|  | case 364:	/* lxvwsx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 4); | 
|  | op->element_size = 4; | 
|  | op->vsx_flags = VSX_SPLAT | VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 396:	/* stxvx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(STORE_VSX, 0, 16); | 
|  | op->element_size = 16; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 397:	/* stxvl */ | 
|  | case 429: {	/* stxvll */ | 
|  | int nb; | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->ea = ra ? regs->gpr[ra] : 0; | 
|  | nb = regs->gpr[rb] & 0xff; | 
|  | if (nb > 16) | 
|  | nb = 16; | 
|  | op->type = MKOP(STORE_VSX, 0, nb); | 
|  | op->element_size = 16; | 
|  | op->vsx_flags = ((instr & 0x20) ? VSX_LDLEFT : 0) | | 
|  | VSX_CHECK_VEC; | 
|  | break; | 
|  | } | 
|  | case 524:	/* lxsspx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 4); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_FPCONV; | 
|  | break; | 
|  |  | 
|  | case 588:	/* lxsdx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 8); | 
|  | op->element_size = 8; | 
|  | break; | 
|  |  | 
|  | case 652:	/* stxsspx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(STORE_VSX, 0, 4); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_FPCONV; | 
|  | break; | 
|  |  | 
|  | case 716:	/* stxsdx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(STORE_VSX, 0, 8); | 
|  | op->element_size = 8; | 
|  | break; | 
|  |  | 
|  | case 780:	/* lxvw4x */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 16); | 
|  | op->element_size = 4; | 
|  | break; | 
|  |  | 
|  | case 781:	/* lxsibzx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 1); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 812:	/* lxvh8x */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 16); | 
|  | op->element_size = 2; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 813:	/* lxsihzx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 2); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 844:	/* lxvd2x */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 16); | 
|  | op->element_size = 8; | 
|  | break; | 
|  |  | 
|  | case 876:	/* lxvb16x */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(LOAD_VSX, 0, 16); | 
|  | op->element_size = 1; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 908:	/* stxvw4x */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(STORE_VSX, 0, 16); | 
|  | op->element_size = 4; | 
|  | break; | 
|  |  | 
|  | case 909:	/* stxsibx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(STORE_VSX, 0, 1); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 940:	/* stxvh8x */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(STORE_VSX, 0, 16); | 
|  | op->element_size = 2; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 941:	/* stxsihx */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(STORE_VSX, 0, 2); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 972:	/* stxvd2x */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(STORE_VSX, 0, 16); | 
|  | op->element_size = 8; | 
|  | break; | 
|  |  | 
|  | case 1004:	/* stxvb16x */ | 
|  | op->reg = rd | ((instr & 1) << 5); | 
|  | op->type = MKOP(STORE_VSX, 0, 16); | 
|  | op->element_size = 1; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | #endif /* CONFIG_VSX */ | 
|  | } | 
|  | break; | 
|  |  | 
|  | case 32:	/* lwz */ | 
|  | case 33:	/* lwzu */ | 
|  | op->type = MKOP(LOAD, u, 4); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 34:	/* lbz */ | 
|  | case 35:	/* lbzu */ | 
|  | op->type = MKOP(LOAD, u, 1); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 36:	/* stw */ | 
|  | case 37:	/* stwu */ | 
|  | op->type = MKOP(STORE, u, 4); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 38:	/* stb */ | 
|  | case 39:	/* stbu */ | 
|  | op->type = MKOP(STORE, u, 1); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 40:	/* lhz */ | 
|  | case 41:	/* lhzu */ | 
|  | op->type = MKOP(LOAD, u, 2); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 42:	/* lha */ | 
|  | case 43:	/* lhau */ | 
|  | op->type = MKOP(LOAD, SIGNEXT | u, 2); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 44:	/* sth */ | 
|  | case 45:	/* sthu */ | 
|  | op->type = MKOP(STORE, u, 2); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 46:	/* lmw */ | 
|  | if (ra >= rd) | 
|  | break;		/* invalid form, ra in range to load */ | 
|  | op->type = MKOP(LOAD_MULTI, 0, 4 * (32 - rd)); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 47:	/* stmw */ | 
|  | op->type = MKOP(STORE_MULTI, 0, 4 * (32 - rd)); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | #ifdef CONFIG_PPC_FPU | 
|  | case 48:	/* lfs */ | 
|  | case 49:	/* lfsu */ | 
|  | op->type = MKOP(LOAD_FP, u | FPCONV, 4); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 50:	/* lfd */ | 
|  | case 51:	/* lfdu */ | 
|  | op->type = MKOP(LOAD_FP, u, 8); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 52:	/* stfs */ | 
|  | case 53:	/* stfsu */ | 
|  | op->type = MKOP(STORE_FP, u | FPCONV, 4); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  |  | 
|  | case 54:	/* stfd */ | 
|  | case 55:	/* stfdu */ | 
|  | op->type = MKOP(STORE_FP, u, 8); | 
|  | op->ea = dform_ea(instr, regs); | 
|  | break; | 
|  | #endif | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 56:	/* lq */ | 
|  | if (!((rd & 1) || (rd == ra))) | 
|  | op->type = MKOP(LOAD, 0, 16); | 
|  | op->ea = dqform_ea(instr, regs); | 
|  | break; | 
|  | #endif | 
|  |  | 
|  | #ifdef CONFIG_VSX | 
|  | case 57:	/* lfdp, lxsd, lxssp */ | 
|  | op->ea = dsform_ea(instr, regs); | 
|  | switch (instr & 3) { | 
|  | case 0:		/* lfdp */ | 
|  | if (rd & 1) | 
|  | break;		/* reg must be even */ | 
|  | op->type = MKOP(LOAD_FP, 0, 16); | 
|  | break; | 
|  | case 2:		/* lxsd */ | 
|  | op->reg = rd + 32; | 
|  | op->type = MKOP(LOAD_VSX, 0, 8); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  | case 3:		/* lxssp */ | 
|  | op->reg = rd + 32; | 
|  | op->type = MKOP(LOAD_VSX, 0, 4); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_FPCONV | VSX_CHECK_VEC; | 
|  | break; | 
|  | } | 
|  | break; | 
|  | #endif /* CONFIG_VSX */ | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 58:	/* ld[u], lwa */ | 
|  | op->ea = dsform_ea(instr, regs); | 
|  | switch (instr & 3) { | 
|  | case 0:		/* ld */ | 
|  | op->type = MKOP(LOAD, 0, 8); | 
|  | break; | 
|  | case 1:		/* ldu */ | 
|  | op->type = MKOP(LOAD, UPDATE, 8); | 
|  | break; | 
|  | case 2:		/* lwa */ | 
|  | op->type = MKOP(LOAD, SIGNEXT, 4); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | #endif | 
|  |  | 
|  | #ifdef CONFIG_VSX | 
|  | case 61:	/* stfdp, lxv, stxsd, stxssp, stxv */ | 
|  | switch (instr & 7) { | 
|  | case 0:		/* stfdp with LSB of DS field = 0 */ | 
|  | case 4:		/* stfdp with LSB of DS field = 1 */ | 
|  | op->ea = dsform_ea(instr, regs); | 
|  | op->type = MKOP(STORE_FP, 0, 16); | 
|  | break; | 
|  |  | 
|  | case 1:		/* lxv */ | 
|  | op->ea = dqform_ea(instr, regs); | 
|  | if (instr & 8) | 
|  | op->reg = rd + 32; | 
|  | op->type = MKOP(LOAD_VSX, 0, 16); | 
|  | op->element_size = 16; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 2:		/* stxsd with LSB of DS field = 0 */ | 
|  | case 6:		/* stxsd with LSB of DS field = 1 */ | 
|  | op->ea = dsform_ea(instr, regs); | 
|  | op->reg = rd + 32; | 
|  | op->type = MKOP(STORE_VSX, 0, 8); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 3:		/* stxssp with LSB of DS field = 0 */ | 
|  | case 7:		/* stxssp with LSB of DS field = 1 */ | 
|  | op->ea = dsform_ea(instr, regs); | 
|  | op->reg = rd + 32; | 
|  | op->type = MKOP(STORE_VSX, 0, 4); | 
|  | op->element_size = 8; | 
|  | op->vsx_flags = VSX_FPCONV | VSX_CHECK_VEC; | 
|  | break; | 
|  |  | 
|  | case 5:		/* stxv */ | 
|  | op->ea = dqform_ea(instr, regs); | 
|  | if (instr & 8) | 
|  | op->reg = rd + 32; | 
|  | op->type = MKOP(STORE_VSX, 0, 16); | 
|  | op->element_size = 16; | 
|  | op->vsx_flags = VSX_CHECK_VEC; | 
|  | break; | 
|  | } | 
|  | break; | 
|  | #endif /* CONFIG_VSX */ | 
|  |  | 
|  | #ifdef __powerpc64__ | 
|  | case 62:	/* std[u] */ | 
|  | op->ea = dsform_ea(instr, regs); | 
|  | switch (instr & 3) { | 
|  | case 0:		/* std */ | 
|  | op->type = MKOP(STORE, 0, 8); | 
|  | break; | 
|  | case 1:		/* stdu */ | 
|  | op->type = MKOP(STORE, UPDATE, 8); | 
|  | break; | 
|  | case 2:		/* stq */ | 
|  | if (!(rd & 1)) | 
|  | op->type = MKOP(STORE, 0, 16); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | #endif /* __powerpc64__ */ | 
|  |  | 
|  | } | 
|  |  | 
|  | #ifdef CONFIG_VSX | 
|  | if ((GETTYPE(op->type) == LOAD_VSX || | 
|  | GETTYPE(op->type) == STORE_VSX) && | 
|  | !cpu_has_feature(CPU_FTR_VSX)) { | 
|  | return -1; | 
|  | } | 
|  | #endif /* CONFIG_VSX */ | 
|  |  | 
|  | return 0; | 
|  |  | 
|  | logical_done: | 
|  | if (instr & 1) | 
|  | set_cr0(regs, op); | 
|  | logical_done_nocc: | 
|  | op->reg = ra; | 
|  | op->type |= SETREG; | 
|  | return 1; | 
|  |  | 
|  | arith_done: | 
|  | if (instr & 1) | 
|  | set_cr0(regs, op); | 
|  | compute_done: | 
|  | op->reg = rd; | 
|  | op->type |= SETREG; | 
|  | return 1; | 
|  |  | 
|  | priv: | 
|  | op->type = INTERRUPT | 0x700; | 
|  | op->val = SRR1_PROGPRIV; | 
|  | return 0; | 
|  |  | 
|  | trap: | 
|  | op->type = INTERRUPT | 0x700; | 
|  | op->val = SRR1_PROGTRAP; | 
|  | return 0; | 
|  | } | 
|  | EXPORT_SYMBOL_GPL(analyse_instr); | 
|  | NOKPROBE_SYMBOL(analyse_instr); | 
|  |  | 
|  | /* | 
|  | * For PPC32 we always use stwu with r1 to change the stack pointer. | 
|  | * So this emulated store may corrupt the exception frame, now we | 
|  | * have to provide the exception frame trampoline, which is pushed | 
|  | * below the kprobed function stack. So we only update gpr[1] but | 
|  | * don't emulate the real store operation. We will do real store | 
|  | * operation safely in exception return code by checking this flag. | 
|  | */ | 
|  | static nokprobe_inline int handle_stack_update(unsigned long ea, struct pt_regs *regs) | 
|  | { | 
|  | #ifdef CONFIG_PPC32 | 
|  | /* | 
|  | * Check if we will touch kernel stack overflow | 
|  | */ | 
|  | if (ea - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) { | 
|  | printk(KERN_CRIT "Can't kprobe this since kernel stack would overflow.\n"); | 
|  | return -EINVAL; | 
|  | } | 
|  | #endif /* CONFIG_PPC32 */ | 
|  | /* | 
|  | * Check if we already set since that means we'll | 
|  | * lose the previous value. | 
|  | */ | 
|  | WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE)); | 
|  | set_thread_flag(TIF_EMULATE_STACK_STORE); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static nokprobe_inline void do_signext(unsigned long *valp, int size) | 
|  | { | 
|  | switch (size) { | 
|  | case 2: | 
|  | *valp = (signed short) *valp; | 
|  | break; | 
|  | case 4: | 
|  | *valp = (signed int) *valp; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static nokprobe_inline void do_byterev(unsigned long *valp, int size) | 
|  | { | 
|  | switch (size) { | 
|  | case 2: | 
|  | *valp = byterev_2(*valp); | 
|  | break; | 
|  | case 4: | 
|  | *valp = byterev_4(*valp); | 
|  | break; | 
|  | #ifdef __powerpc64__ | 
|  | case 8: | 
|  | *valp = byterev_8(*valp); | 
|  | break; | 
|  | #endif | 
|  | } | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Emulate an instruction that can be executed just by updating | 
|  | * fields in *regs. | 
|  | */ | 
|  | void emulate_update_regs(struct pt_regs *regs, struct instruction_op *op) | 
|  | { | 
|  | unsigned long next_pc; | 
|  |  | 
|  | next_pc = truncate_if_32bit(regs->msr, regs->nip + 4); | 
|  | switch (GETTYPE(op->type)) { | 
|  | case COMPUTE: | 
|  | if (op->type & SETREG) | 
|  | regs->gpr[op->reg] = op->val; | 
|  | if (op->type & SETCC) | 
|  | regs->ccr = op->ccval; | 
|  | if (op->type & SETXER) | 
|  | regs->xer = op->xerval; | 
|  | break; | 
|  |  | 
|  | case BRANCH: | 
|  | if (op->type & SETLK) | 
|  | regs->link = next_pc; | 
|  | if (op->type & BRTAKEN) | 
|  | next_pc = op->val; | 
|  | if (op->type & DECCTR) | 
|  | --regs->ctr; | 
|  | break; | 
|  |  | 
|  | case BARRIER: | 
|  | switch (op->type & BARRIER_MASK) { | 
|  | case BARRIER_SYNC: | 
|  | mb(); | 
|  | break; | 
|  | case BARRIER_ISYNC: | 
|  | isync(); | 
|  | break; | 
|  | case BARRIER_EIEIO: | 
|  | eieio(); | 
|  | break; | 
|  | case BARRIER_LWSYNC: | 
|  | asm volatile("lwsync" : : : "memory"); | 
|  | break; | 
|  | case BARRIER_PTESYNC: | 
|  | asm volatile("ptesync" : : : "memory"); | 
|  | break; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case MFSPR: | 
|  | switch (op->spr) { | 
|  | case SPRN_XER: | 
|  | regs->gpr[op->reg] = regs->xer & 0xffffffffUL; | 
|  | break; | 
|  | case SPRN_LR: | 
|  | regs->gpr[op->reg] = regs->link; | 
|  | break; | 
|  | case SPRN_CTR: | 
|  | regs->gpr[op->reg] = regs->ctr; | 
|  | break; | 
|  | default: | 
|  | WARN_ON_ONCE(1); | 
|  | } | 
|  | break; | 
|  |  | 
|  | case MTSPR: | 
|  | switch (op->spr) { | 
|  | case SPRN_XER: | 
|  | regs->xer = op->val & 0xffffffffUL; | 
|  | break; | 
|  | case SPRN_LR: | 
|  | regs->link = op->val; | 
|  | break; | 
|  | case SPRN_CTR: | 
|  | regs->ctr = op->val; | 
|  | break; | 
|  | default: | 
|  | WARN_ON_ONCE(1); | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | WARN_ON_ONCE(1); | 
|  | } | 
|  | regs->nip = next_pc; | 
|  | } | 
|  | NOKPROBE_SYMBOL(emulate_update_regs); | 
|  |  | 
|  | /* | 
|  | * Emulate a previously-analysed load or store instruction. | 
|  | * Return values are: | 
|  | * 0 = instruction emulated successfully | 
|  | * -EFAULT = address out of range or access faulted (regs->dar | 
|  | *	     contains the faulting address) | 
|  | * -EACCES = misaligned access, instruction requires alignment | 
|  | * -EINVAL = unknown operation in *op | 
|  | */ | 
|  | int emulate_loadstore(struct pt_regs *regs, struct instruction_op *op) | 
|  | { | 
|  | int err, size, type; | 
|  | int i, rd, nb; | 
|  | unsigned int cr; | 
|  | unsigned long val; | 
|  | unsigned long ea; | 
|  | bool cross_endian; | 
|  |  | 
|  | err = 0; | 
|  | size = GETSIZE(op->type); | 
|  | type = GETTYPE(op->type); | 
|  | cross_endian = (regs->msr & MSR_LE) != (MSR_KERNEL & MSR_LE); | 
|  | ea = truncate_if_32bit(regs->msr, op->ea); | 
|  |  | 
|  | switch (type) { | 
|  | case LARX: | 
|  | if (ea & (size - 1)) | 
|  | return -EACCES;		/* can't handle misaligned */ | 
|  | if (!address_ok(regs, ea, size)) | 
|  | return -EFAULT; | 
|  | err = 0; | 
|  | val = 0; | 
|  | switch (size) { | 
|  | #ifdef __powerpc64__ | 
|  | case 1: | 
|  | __get_user_asmx(val, ea, err, "lbarx"); | 
|  | break; | 
|  | case 2: | 
|  | __get_user_asmx(val, ea, err, "lharx"); | 
|  | break; | 
|  | #endif | 
|  | case 4: | 
|  | __get_user_asmx(val, ea, err, "lwarx"); | 
|  | break; | 
|  | #ifdef __powerpc64__ | 
|  | case 8: | 
|  | __get_user_asmx(val, ea, err, "ldarx"); | 
|  | break; | 
|  | case 16: | 
|  | err = do_lqarx(ea, ®s->gpr[op->reg]); | 
|  | break; | 
|  | #endif | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | if (err) { | 
|  | regs->dar = ea; | 
|  | break; | 
|  | } | 
|  | if (size < 16) | 
|  | regs->gpr[op->reg] = val; | 
|  | break; | 
|  |  | 
|  | case STCX: | 
|  | if (ea & (size - 1)) | 
|  | return -EACCES;		/* can't handle misaligned */ | 
|  | if (!address_ok(regs, ea, size)) | 
|  | return -EFAULT; | 
|  | err = 0; | 
|  | switch (size) { | 
|  | #ifdef __powerpc64__ | 
|  | case 1: | 
|  | __put_user_asmx(op->val, ea, err, "stbcx.", cr); | 
|  | break; | 
|  | case 2: | 
|  | __put_user_asmx(op->val, ea, err, "stbcx.", cr); | 
|  | break; | 
|  | #endif | 
|  | case 4: | 
|  | __put_user_asmx(op->val, ea, err, "stwcx.", cr); | 
|  | break; | 
|  | #ifdef __powerpc64__ | 
|  | case 8: | 
|  | __put_user_asmx(op->val, ea, err, "stdcx.", cr); | 
|  | break; | 
|  | case 16: | 
|  | err = do_stqcx(ea, regs->gpr[op->reg], | 
|  | regs->gpr[op->reg + 1], &cr); | 
|  | break; | 
|  | #endif | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  | if (!err) | 
|  | regs->ccr = (regs->ccr & 0x0fffffff) | | 
|  | (cr & 0xe0000000) | | 
|  | ((regs->xer >> 3) & 0x10000000); | 
|  | else | 
|  | regs->dar = ea; | 
|  | break; | 
|  |  | 
|  | case LOAD: | 
|  | #ifdef __powerpc64__ | 
|  | if (size == 16) { | 
|  | err = emulate_lq(regs, ea, op->reg, cross_endian); | 
|  | break; | 
|  | } | 
|  | #endif | 
|  | err = read_mem(®s->gpr[op->reg], ea, size, regs); | 
|  | if (!err) { | 
|  | if (op->type & SIGNEXT) | 
|  | do_signext(®s->gpr[op->reg], size); | 
|  | if ((op->type & BYTEREV) == (cross_endian ? 0 : BYTEREV)) | 
|  | do_byterev(®s->gpr[op->reg], size); | 
|  | } | 
|  | break; | 
|  |  | 
|  | #ifdef CONFIG_PPC_FPU | 
|  | case LOAD_FP: | 
|  | /* | 
|  | * If the instruction is in userspace, we can emulate it even | 
|  | * if the VMX state is not live, because we have the state | 
|  | * stored in the thread_struct.  If the instruction is in | 
|  | * the kernel, we must not touch the state in the thread_struct. | 
|  | */ | 
|  | if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_FP)) | 
|  | return 0; | 
|  | err = do_fp_load(op, ea, regs, cross_endian); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_ALTIVEC | 
|  | case LOAD_VMX: | 
|  | if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_VEC)) | 
|  | return 0; | 
|  | err = do_vec_load(op->reg, ea, size, regs, cross_endian); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VSX | 
|  | case LOAD_VSX: { | 
|  | unsigned long msrbit = MSR_VSX; | 
|  |  | 
|  | /* | 
|  | * Some VSX instructions check the MSR_VEC bit rather than MSR_VSX | 
|  | * when the target of the instruction is a vector register. | 
|  | */ | 
|  | if (op->reg >= 32 && (op->vsx_flags & VSX_CHECK_VEC)) | 
|  | msrbit = MSR_VEC; | 
|  | if (!(regs->msr & MSR_PR) && !(regs->msr & msrbit)) | 
|  | return 0; | 
|  | err = do_vsx_load(op, ea, regs, cross_endian); | 
|  | break; | 
|  | } | 
|  | #endif | 
|  | case LOAD_MULTI: | 
|  | if (!address_ok(regs, ea, size)) | 
|  | return -EFAULT; | 
|  | rd = op->reg; | 
|  | for (i = 0; i < size; i += 4) { | 
|  | unsigned int v32 = 0; | 
|  |  | 
|  | nb = size - i; | 
|  | if (nb > 4) | 
|  | nb = 4; | 
|  | err = copy_mem_in((u8 *) &v32, ea, nb, regs); | 
|  | if (err) | 
|  | break; | 
|  | if (unlikely(cross_endian)) | 
|  | v32 = byterev_4(v32); | 
|  | regs->gpr[rd] = v32; | 
|  | ea += 4; | 
|  | /* reg number wraps from 31 to 0 for lsw[ix] */ | 
|  | rd = (rd + 1) & 0x1f; | 
|  | } | 
|  | break; | 
|  |  | 
|  | case STORE: | 
|  | #ifdef __powerpc64__ | 
|  | if (size == 16) { | 
|  | err = emulate_stq(regs, ea, op->reg, cross_endian); | 
|  | break; | 
|  | } | 
|  | #endif | 
|  | if ((op->type & UPDATE) && size == sizeof(long) && | 
|  | op->reg == 1 && op->update_reg == 1 && | 
|  | !(regs->msr & MSR_PR) && | 
|  | ea >= regs->gpr[1] - STACK_INT_FRAME_SIZE) { | 
|  | err = handle_stack_update(ea, regs); | 
|  | break; | 
|  | } | 
|  | if (unlikely(cross_endian)) | 
|  | do_byterev(&op->val, size); | 
|  | err = write_mem(op->val, ea, size, regs); | 
|  | break; | 
|  |  | 
|  | #ifdef CONFIG_PPC_FPU | 
|  | case STORE_FP: | 
|  | if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_FP)) | 
|  | return 0; | 
|  | err = do_fp_store(op, ea, regs, cross_endian); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_ALTIVEC | 
|  | case STORE_VMX: | 
|  | if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_VEC)) | 
|  | return 0; | 
|  | err = do_vec_store(op->reg, ea, size, regs, cross_endian); | 
|  | break; | 
|  | #endif | 
|  | #ifdef CONFIG_VSX | 
|  | case STORE_VSX: { | 
|  | unsigned long msrbit = MSR_VSX; | 
|  |  | 
|  | /* | 
|  | * Some VSX instructions check the MSR_VEC bit rather than MSR_VSX | 
|  | * when the target of the instruction is a vector register. | 
|  | */ | 
|  | if (op->reg >= 32 && (op->vsx_flags & VSX_CHECK_VEC)) | 
|  | msrbit = MSR_VEC; | 
|  | if (!(regs->msr & MSR_PR) && !(regs->msr & msrbit)) | 
|  | return 0; | 
|  | err = do_vsx_store(op, ea, regs, cross_endian); | 
|  | break; | 
|  | } | 
|  | #endif | 
|  | case STORE_MULTI: | 
|  | if (!address_ok(regs, ea, size)) | 
|  | return -EFAULT; | 
|  | rd = op->reg; | 
|  | for (i = 0; i < size; i += 4) { | 
|  | unsigned int v32 = regs->gpr[rd]; | 
|  |  | 
|  | nb = size - i; | 
|  | if (nb > 4) | 
|  | nb = 4; | 
|  | if (unlikely(cross_endian)) | 
|  | v32 = byterev_4(v32); | 
|  | err = copy_mem_out((u8 *) &v32, ea, nb, regs); | 
|  | if (err) | 
|  | break; | 
|  | ea += 4; | 
|  | /* reg number wraps from 31 to 0 for stsw[ix] */ | 
|  | rd = (rd + 1) & 0x1f; | 
|  | } | 
|  | break; | 
|  |  | 
|  | default: | 
|  | return -EINVAL; | 
|  | } | 
|  |  | 
|  | if (err) | 
|  | return err; | 
|  |  | 
|  | if (op->type & UPDATE) | 
|  | regs->gpr[op->update_reg] = op->ea; | 
|  |  | 
|  | return 0; | 
|  | } | 
|  | NOKPROBE_SYMBOL(emulate_loadstore); | 
|  |  | 
|  | /* | 
|  | * Emulate instructions that cause a transfer of control, | 
|  | * loads and stores, and a few other instructions. | 
|  | * Returns 1 if the step was emulated, 0 if not, | 
|  | * or -1 if the instruction is one that should not be stepped, | 
|  | * such as an rfid, or a mtmsrd that would clear MSR_RI. | 
|  | */ | 
|  | int emulate_step(struct pt_regs *regs, unsigned int instr) | 
|  | { | 
|  | struct instruction_op op; | 
|  | int r, err, type; | 
|  | unsigned long val; | 
|  | unsigned long ea; | 
|  |  | 
|  | r = analyse_instr(&op, regs, instr); | 
|  | if (r < 0) | 
|  | return r; | 
|  | if (r > 0) { | 
|  | emulate_update_regs(regs, &op); | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | err = 0; | 
|  | type = GETTYPE(op.type); | 
|  |  | 
|  | if (OP_IS_LOAD_STORE(type)) { | 
|  | err = emulate_loadstore(regs, &op); | 
|  | if (err) | 
|  | return 0; | 
|  | goto instr_done; | 
|  | } | 
|  |  | 
|  | switch (type) { | 
|  | case CACHEOP: | 
|  | ea = truncate_if_32bit(regs->msr, op.ea); | 
|  | if (!address_ok(regs, ea, 8)) | 
|  | return 0; | 
|  | switch (op.type & CACHEOP_MASK) { | 
|  | case DCBST: | 
|  | __cacheop_user_asmx(ea, err, "dcbst"); | 
|  | break; | 
|  | case DCBF: | 
|  | __cacheop_user_asmx(ea, err, "dcbf"); | 
|  | break; | 
|  | case DCBTST: | 
|  | if (op.reg == 0) | 
|  | prefetchw((void *) ea); | 
|  | break; | 
|  | case DCBT: | 
|  | if (op.reg == 0) | 
|  | prefetch((void *) ea); | 
|  | break; | 
|  | case ICBI: | 
|  | __cacheop_user_asmx(ea, err, "icbi"); | 
|  | break; | 
|  | case DCBZ: | 
|  | err = emulate_dcbz(ea, regs); | 
|  | break; | 
|  | } | 
|  | if (err) { | 
|  | regs->dar = ea; | 
|  | return 0; | 
|  | } | 
|  | goto instr_done; | 
|  |  | 
|  | case MFMSR: | 
|  | regs->gpr[op.reg] = regs->msr & MSR_MASK; | 
|  | goto instr_done; | 
|  |  | 
|  | case MTMSR: | 
|  | val = regs->gpr[op.reg]; | 
|  | if ((val & MSR_RI) == 0) | 
|  | /* can't step mtmsr[d] that would clear MSR_RI */ | 
|  | return -1; | 
|  | /* here op.val is the mask of bits to change */ | 
|  | regs->msr = (regs->msr & ~op.val) | (val & op.val); | 
|  | goto instr_done; | 
|  |  | 
|  | #ifdef CONFIG_PPC64 | 
|  | case SYSCALL:	/* sc */ | 
|  | /* | 
|  | * N.B. this uses knowledge about how the syscall | 
|  | * entry code works.  If that is changed, this will | 
|  | * need to be changed also. | 
|  | */ | 
|  | if (regs->gpr[0] == 0x1ebe && | 
|  | cpu_has_feature(CPU_FTR_REAL_LE)) { | 
|  | regs->msr ^= MSR_LE; | 
|  | goto instr_done; | 
|  | } | 
|  | regs->gpr[9] = regs->gpr[13]; | 
|  | regs->gpr[10] = MSR_KERNEL; | 
|  | regs->gpr[11] = regs->nip + 4; | 
|  | regs->gpr[12] = regs->msr & MSR_MASK; | 
|  | regs->gpr[13] = (unsigned long) get_paca(); | 
|  | regs->nip = (unsigned long) &system_call_common; | 
|  | regs->msr = MSR_KERNEL; | 
|  | return 1; | 
|  |  | 
|  | case RFI: | 
|  | return -1; | 
|  | #endif | 
|  | } | 
|  | return 0; | 
|  |  | 
|  | instr_done: | 
|  | regs->nip = truncate_if_32bit(regs->msr, regs->nip + 4); | 
|  | return 1; | 
|  | } | 
|  | NOKPROBE_SYMBOL(emulate_step); |