18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Single-step support.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2004 Paul Mackerras <paulus@au.ibm.com>, IBM
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci#include <linux/kernel.h>
88c2ecf20Sopenharmony_ci#include <linux/kprobes.h>
98c2ecf20Sopenharmony_ci#include <linux/ptrace.h>
108c2ecf20Sopenharmony_ci#include <linux/prefetch.h>
118c2ecf20Sopenharmony_ci#include <asm/sstep.h>
128c2ecf20Sopenharmony_ci#include <asm/processor.h>
138c2ecf20Sopenharmony_ci#include <linux/uaccess.h>
148c2ecf20Sopenharmony_ci#include <asm/cpu_has_feature.h>
158c2ecf20Sopenharmony_ci#include <asm/cputable.h>
168c2ecf20Sopenharmony_ci#include <asm/disassemble.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ciextern char system_call_common[];
198c2ecf20Sopenharmony_ciextern char system_call_vectored_emulate[];
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
228c2ecf20Sopenharmony_ci/* Bits in SRR1 that are copied from MSR */
238c2ecf20Sopenharmony_ci#define MSR_MASK	0xffffffff87c0ffffUL
248c2ecf20Sopenharmony_ci#else
258c2ecf20Sopenharmony_ci#define MSR_MASK	0x87c0ffff
268c2ecf20Sopenharmony_ci#endif
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ci/* Bits in XER */
298c2ecf20Sopenharmony_ci#define XER_SO		0x80000000U
308c2ecf20Sopenharmony_ci#define XER_OV		0x40000000U
318c2ecf20Sopenharmony_ci#define XER_CA		0x20000000U
328c2ecf20Sopenharmony_ci#define XER_OV32	0x00080000U
338c2ecf20Sopenharmony_ci#define XER_CA32	0x00040000U
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_FPU
368c2ecf20Sopenharmony_ci/*
378c2ecf20Sopenharmony_ci * Functions in ldstfp.S
388c2ecf20Sopenharmony_ci */
398c2ecf20Sopenharmony_ciextern void get_fpr(int rn, double *p);
408c2ecf20Sopenharmony_ciextern void put_fpr(int rn, const double *p);
418c2ecf20Sopenharmony_ciextern void get_vr(int rn, __vector128 *p);
428c2ecf20Sopenharmony_ciextern void put_vr(int rn, __vector128 *p);
438c2ecf20Sopenharmony_ciextern void load_vsrn(int vsr, const void *p);
448c2ecf20Sopenharmony_ciextern void store_vsrn(int vsr, void *p);
458c2ecf20Sopenharmony_ciextern void conv_sp_to_dp(const float *sp, double *dp);
468c2ecf20Sopenharmony_ciextern void conv_dp_to_sp(const double *dp, float *sp);
478c2ecf20Sopenharmony_ci#endif
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#ifdef __powerpc64__
508c2ecf20Sopenharmony_ci/*
518c2ecf20Sopenharmony_ci * Functions in quad.S
528c2ecf20Sopenharmony_ci */
538c2ecf20Sopenharmony_ciextern int do_lq(unsigned long ea, unsigned long *regs);
548c2ecf20Sopenharmony_ciextern int do_stq(unsigned long ea, unsigned long val0, unsigned long val1);
558c2ecf20Sopenharmony_ciextern int do_lqarx(unsigned long ea, unsigned long *regs);
568c2ecf20Sopenharmony_ciextern int do_stqcx(unsigned long ea, unsigned long val0, unsigned long val1,
578c2ecf20Sopenharmony_ci		    unsigned int *crp);
588c2ecf20Sopenharmony_ci#endif
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci#ifdef __LITTLE_ENDIAN__
618c2ecf20Sopenharmony_ci#define IS_LE	1
628c2ecf20Sopenharmony_ci#define IS_BE	0
638c2ecf20Sopenharmony_ci#else
648c2ecf20Sopenharmony_ci#define IS_LE	0
658c2ecf20Sopenharmony_ci#define IS_BE	1
668c2ecf20Sopenharmony_ci#endif
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci/*
698c2ecf20Sopenharmony_ci * Emulate the truncation of 64 bit values in 32-bit mode.
708c2ecf20Sopenharmony_ci */
718c2ecf20Sopenharmony_cistatic nokprobe_inline unsigned long truncate_if_32bit(unsigned long msr,
728c2ecf20Sopenharmony_ci							unsigned long val)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci#ifdef __powerpc64__
758c2ecf20Sopenharmony_ci	if ((msr & MSR_64BIT) == 0)
768c2ecf20Sopenharmony_ci		val &= 0xffffffffUL;
778c2ecf20Sopenharmony_ci#endif
788c2ecf20Sopenharmony_ci	return val;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci/*
828c2ecf20Sopenharmony_ci * Determine whether a conditional branch instruction would branch.
838c2ecf20Sopenharmony_ci */
848c2ecf20Sopenharmony_cistatic nokprobe_inline int branch_taken(unsigned int instr,
858c2ecf20Sopenharmony_ci					const struct pt_regs *regs,
868c2ecf20Sopenharmony_ci					struct instruction_op *op)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	unsigned int bo = (instr >> 21) & 0x1f;
898c2ecf20Sopenharmony_ci	unsigned int bi;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	if ((bo & 4) == 0) {
928c2ecf20Sopenharmony_ci		/* decrement counter */
938c2ecf20Sopenharmony_ci		op->type |= DECCTR;
948c2ecf20Sopenharmony_ci		if (((bo >> 1) & 1) ^ (regs->ctr == 1))
958c2ecf20Sopenharmony_ci			return 0;
968c2ecf20Sopenharmony_ci	}
978c2ecf20Sopenharmony_ci	if ((bo & 0x10) == 0) {
988c2ecf20Sopenharmony_ci		/* check bit from CR */
998c2ecf20Sopenharmony_ci		bi = (instr >> 16) & 0x1f;
1008c2ecf20Sopenharmony_ci		if (((regs->ccr >> (31 - bi)) & 1) != ((bo >> 3) & 1))
1018c2ecf20Sopenharmony_ci			return 0;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci	return 1;
1048c2ecf20Sopenharmony_ci}
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic nokprobe_inline long address_ok(struct pt_regs *regs,
1078c2ecf20Sopenharmony_ci				       unsigned long ea, int nb)
1088c2ecf20Sopenharmony_ci{
1098c2ecf20Sopenharmony_ci	if (!user_mode(regs))
1108c2ecf20Sopenharmony_ci		return 1;
1118c2ecf20Sopenharmony_ci	if (access_ok((void __user *)ea, nb))
1128c2ecf20Sopenharmony_ci		return 1;
1138c2ecf20Sopenharmony_ci	if (access_ok((void __user *)ea, 1))
1148c2ecf20Sopenharmony_ci		/* Access overlaps the end of the user region */
1158c2ecf20Sopenharmony_ci		regs->dar = TASK_SIZE_MAX - 1;
1168c2ecf20Sopenharmony_ci	else
1178c2ecf20Sopenharmony_ci		regs->dar = ea;
1188c2ecf20Sopenharmony_ci	return 0;
1198c2ecf20Sopenharmony_ci}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci/*
1228c2ecf20Sopenharmony_ci * Calculate effective address for a D-form instruction
1238c2ecf20Sopenharmony_ci */
1248c2ecf20Sopenharmony_cistatic nokprobe_inline unsigned long dform_ea(unsigned int instr,
1258c2ecf20Sopenharmony_ci					      const struct pt_regs *regs)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	int ra;
1288c2ecf20Sopenharmony_ci	unsigned long ea;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	ra = (instr >> 16) & 0x1f;
1318c2ecf20Sopenharmony_ci	ea = (signed short) instr;		/* sign-extend */
1328c2ecf20Sopenharmony_ci	if (ra)
1338c2ecf20Sopenharmony_ci		ea += regs->gpr[ra];
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	return ea;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci#ifdef __powerpc64__
1398c2ecf20Sopenharmony_ci/*
1408c2ecf20Sopenharmony_ci * Calculate effective address for a DS-form instruction
1418c2ecf20Sopenharmony_ci */
1428c2ecf20Sopenharmony_cistatic nokprobe_inline unsigned long dsform_ea(unsigned int instr,
1438c2ecf20Sopenharmony_ci					       const struct pt_regs *regs)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	int ra;
1468c2ecf20Sopenharmony_ci	unsigned long ea;
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci	ra = (instr >> 16) & 0x1f;
1498c2ecf20Sopenharmony_ci	ea = (signed short) (instr & ~3);	/* sign-extend */
1508c2ecf20Sopenharmony_ci	if (ra)
1518c2ecf20Sopenharmony_ci		ea += regs->gpr[ra];
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	return ea;
1548c2ecf20Sopenharmony_ci}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci/*
1578c2ecf20Sopenharmony_ci * Calculate effective address for a DQ-form instruction
1588c2ecf20Sopenharmony_ci */
1598c2ecf20Sopenharmony_cistatic nokprobe_inline unsigned long dqform_ea(unsigned int instr,
1608c2ecf20Sopenharmony_ci					       const struct pt_regs *regs)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	int ra;
1638c2ecf20Sopenharmony_ci	unsigned long ea;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	ra = (instr >> 16) & 0x1f;
1668c2ecf20Sopenharmony_ci	ea = (signed short) (instr & ~0xf);	/* sign-extend */
1678c2ecf20Sopenharmony_ci	if (ra)
1688c2ecf20Sopenharmony_ci		ea += regs->gpr[ra];
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci	return ea;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci#endif /* __powerpc64 */
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci/*
1758c2ecf20Sopenharmony_ci * Calculate effective address for an X-form instruction
1768c2ecf20Sopenharmony_ci */
1778c2ecf20Sopenharmony_cistatic nokprobe_inline unsigned long xform_ea(unsigned int instr,
1788c2ecf20Sopenharmony_ci					      const struct pt_regs *regs)
1798c2ecf20Sopenharmony_ci{
1808c2ecf20Sopenharmony_ci	int ra, rb;
1818c2ecf20Sopenharmony_ci	unsigned long ea;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	ra = (instr >> 16) & 0x1f;
1848c2ecf20Sopenharmony_ci	rb = (instr >> 11) & 0x1f;
1858c2ecf20Sopenharmony_ci	ea = regs->gpr[rb];
1868c2ecf20Sopenharmony_ci	if (ra)
1878c2ecf20Sopenharmony_ci		ea += regs->gpr[ra];
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	return ea;
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci/*
1938c2ecf20Sopenharmony_ci * Calculate effective address for a MLS:D-form / 8LS:D-form
1948c2ecf20Sopenharmony_ci * prefixed instruction
1958c2ecf20Sopenharmony_ci */
1968c2ecf20Sopenharmony_cistatic nokprobe_inline unsigned long mlsd_8lsd_ea(unsigned int instr,
1978c2ecf20Sopenharmony_ci						  unsigned int suffix,
1988c2ecf20Sopenharmony_ci						  const struct pt_regs *regs)
1998c2ecf20Sopenharmony_ci{
2008c2ecf20Sopenharmony_ci	int ra, prefix_r;
2018c2ecf20Sopenharmony_ci	unsigned int  dd;
2028c2ecf20Sopenharmony_ci	unsigned long ea, d0, d1, d;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	prefix_r = GET_PREFIX_R(instr);
2058c2ecf20Sopenharmony_ci	ra = GET_PREFIX_RA(suffix);
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	d0 = instr & 0x3ffff;
2088c2ecf20Sopenharmony_ci	d1 = suffix & 0xffff;
2098c2ecf20Sopenharmony_ci	d = (d0 << 16) | d1;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	/*
2128c2ecf20Sopenharmony_ci	 * sign extend a 34 bit number
2138c2ecf20Sopenharmony_ci	 */
2148c2ecf20Sopenharmony_ci	dd = (unsigned int)(d >> 2);
2158c2ecf20Sopenharmony_ci	ea = (signed int)dd;
2168c2ecf20Sopenharmony_ci	ea = (ea << 2) | (d & 0x3);
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	if (!prefix_r && ra)
2198c2ecf20Sopenharmony_ci		ea += regs->gpr[ra];
2208c2ecf20Sopenharmony_ci	else if (!prefix_r && !ra)
2218c2ecf20Sopenharmony_ci		; /* Leave ea as is */
2228c2ecf20Sopenharmony_ci	else if (prefix_r)
2238c2ecf20Sopenharmony_ci		ea += regs->nip;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	/*
2268c2ecf20Sopenharmony_ci	 * (prefix_r && ra) is an invalid form. Should already be
2278c2ecf20Sopenharmony_ci	 * checked for by caller!
2288c2ecf20Sopenharmony_ci	 */
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	return ea;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/*
2348c2ecf20Sopenharmony_ci * Return the largest power of 2, not greater than sizeof(unsigned long),
2358c2ecf20Sopenharmony_ci * such that x is a multiple of it.
2368c2ecf20Sopenharmony_ci */
2378c2ecf20Sopenharmony_cistatic nokprobe_inline unsigned long max_align(unsigned long x)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	x |= sizeof(unsigned long);
2408c2ecf20Sopenharmony_ci	return x & -x;		/* isolates rightmost bit */
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic nokprobe_inline unsigned long byterev_2(unsigned long x)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	return ((x >> 8) & 0xff) | ((x & 0xff) << 8);
2468c2ecf20Sopenharmony_ci}
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_cistatic nokprobe_inline unsigned long byterev_4(unsigned long x)
2498c2ecf20Sopenharmony_ci{
2508c2ecf20Sopenharmony_ci	return ((x >> 24) & 0xff) | ((x >> 8) & 0xff00) |
2518c2ecf20Sopenharmony_ci		((x & 0xff00) << 8) | ((x & 0xff) << 24);
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci#ifdef __powerpc64__
2558c2ecf20Sopenharmony_cistatic nokprobe_inline unsigned long byterev_8(unsigned long x)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	return (byterev_4(x) << 32) | byterev_4(x >> 32);
2588c2ecf20Sopenharmony_ci}
2598c2ecf20Sopenharmony_ci#endif
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_cistatic nokprobe_inline void do_byte_reverse(void *ptr, int nb)
2628c2ecf20Sopenharmony_ci{
2638c2ecf20Sopenharmony_ci	switch (nb) {
2648c2ecf20Sopenharmony_ci	case 2:
2658c2ecf20Sopenharmony_ci		*(u16 *)ptr = byterev_2(*(u16 *)ptr);
2668c2ecf20Sopenharmony_ci		break;
2678c2ecf20Sopenharmony_ci	case 4:
2688c2ecf20Sopenharmony_ci		*(u32 *)ptr = byterev_4(*(u32 *)ptr);
2698c2ecf20Sopenharmony_ci		break;
2708c2ecf20Sopenharmony_ci#ifdef __powerpc64__
2718c2ecf20Sopenharmony_ci	case 8:
2728c2ecf20Sopenharmony_ci		*(unsigned long *)ptr = byterev_8(*(unsigned long *)ptr);
2738c2ecf20Sopenharmony_ci		break;
2748c2ecf20Sopenharmony_ci	case 16: {
2758c2ecf20Sopenharmony_ci		unsigned long *up = (unsigned long *)ptr;
2768c2ecf20Sopenharmony_ci		unsigned long tmp;
2778c2ecf20Sopenharmony_ci		tmp = byterev_8(up[0]);
2788c2ecf20Sopenharmony_ci		up[0] = byterev_8(up[1]);
2798c2ecf20Sopenharmony_ci		up[1] = tmp;
2808c2ecf20Sopenharmony_ci		break;
2818c2ecf20Sopenharmony_ci	}
2828c2ecf20Sopenharmony_ci#endif
2838c2ecf20Sopenharmony_ci	default:
2848c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci}
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_cistatic nokprobe_inline int read_mem_aligned(unsigned long *dest,
2898c2ecf20Sopenharmony_ci					    unsigned long ea, int nb,
2908c2ecf20Sopenharmony_ci					    struct pt_regs *regs)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	int err = 0;
2938c2ecf20Sopenharmony_ci	unsigned long x = 0;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	switch (nb) {
2968c2ecf20Sopenharmony_ci	case 1:
2978c2ecf20Sopenharmony_ci		err = __get_user(x, (unsigned char __user *) ea);
2988c2ecf20Sopenharmony_ci		break;
2998c2ecf20Sopenharmony_ci	case 2:
3008c2ecf20Sopenharmony_ci		err = __get_user(x, (unsigned short __user *) ea);
3018c2ecf20Sopenharmony_ci		break;
3028c2ecf20Sopenharmony_ci	case 4:
3038c2ecf20Sopenharmony_ci		err = __get_user(x, (unsigned int __user *) ea);
3048c2ecf20Sopenharmony_ci		break;
3058c2ecf20Sopenharmony_ci#ifdef __powerpc64__
3068c2ecf20Sopenharmony_ci	case 8:
3078c2ecf20Sopenharmony_ci		err = __get_user(x, (unsigned long __user *) ea);
3088c2ecf20Sopenharmony_ci		break;
3098c2ecf20Sopenharmony_ci#endif
3108c2ecf20Sopenharmony_ci	}
3118c2ecf20Sopenharmony_ci	if (!err)
3128c2ecf20Sopenharmony_ci		*dest = x;
3138c2ecf20Sopenharmony_ci	else
3148c2ecf20Sopenharmony_ci		regs->dar = ea;
3158c2ecf20Sopenharmony_ci	return err;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci/*
3198c2ecf20Sopenharmony_ci * Copy from userspace to a buffer, using the largest possible
3208c2ecf20Sopenharmony_ci * aligned accesses, up to sizeof(long).
3218c2ecf20Sopenharmony_ci */
3228c2ecf20Sopenharmony_cistatic nokprobe_inline int copy_mem_in(u8 *dest, unsigned long ea, int nb,
3238c2ecf20Sopenharmony_ci				       struct pt_regs *regs)
3248c2ecf20Sopenharmony_ci{
3258c2ecf20Sopenharmony_ci	int err = 0;
3268c2ecf20Sopenharmony_ci	int c;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	for (; nb > 0; nb -= c) {
3298c2ecf20Sopenharmony_ci		c = max_align(ea);
3308c2ecf20Sopenharmony_ci		if (c > nb)
3318c2ecf20Sopenharmony_ci			c = max_align(nb);
3328c2ecf20Sopenharmony_ci		switch (c) {
3338c2ecf20Sopenharmony_ci		case 1:
3348c2ecf20Sopenharmony_ci			err = __get_user(*dest, (unsigned char __user *) ea);
3358c2ecf20Sopenharmony_ci			break;
3368c2ecf20Sopenharmony_ci		case 2:
3378c2ecf20Sopenharmony_ci			err = __get_user(*(u16 *)dest,
3388c2ecf20Sopenharmony_ci					 (unsigned short __user *) ea);
3398c2ecf20Sopenharmony_ci			break;
3408c2ecf20Sopenharmony_ci		case 4:
3418c2ecf20Sopenharmony_ci			err = __get_user(*(u32 *)dest,
3428c2ecf20Sopenharmony_ci					 (unsigned int __user *) ea);
3438c2ecf20Sopenharmony_ci			break;
3448c2ecf20Sopenharmony_ci#ifdef __powerpc64__
3458c2ecf20Sopenharmony_ci		case 8:
3468c2ecf20Sopenharmony_ci			err = __get_user(*(unsigned long *)dest,
3478c2ecf20Sopenharmony_ci					 (unsigned long __user *) ea);
3488c2ecf20Sopenharmony_ci			break;
3498c2ecf20Sopenharmony_ci#endif
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci		if (err) {
3528c2ecf20Sopenharmony_ci			regs->dar = ea;
3538c2ecf20Sopenharmony_ci			return err;
3548c2ecf20Sopenharmony_ci		}
3558c2ecf20Sopenharmony_ci		dest += c;
3568c2ecf20Sopenharmony_ci		ea += c;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci	return 0;
3598c2ecf20Sopenharmony_ci}
3608c2ecf20Sopenharmony_ci
3618c2ecf20Sopenharmony_cistatic nokprobe_inline int read_mem_unaligned(unsigned long *dest,
3628c2ecf20Sopenharmony_ci					      unsigned long ea, int nb,
3638c2ecf20Sopenharmony_ci					      struct pt_regs *regs)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	union {
3668c2ecf20Sopenharmony_ci		unsigned long ul;
3678c2ecf20Sopenharmony_ci		u8 b[sizeof(unsigned long)];
3688c2ecf20Sopenharmony_ci	} u;
3698c2ecf20Sopenharmony_ci	int i;
3708c2ecf20Sopenharmony_ci	int err;
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci	u.ul = 0;
3738c2ecf20Sopenharmony_ci	i = IS_BE ? sizeof(unsigned long) - nb : 0;
3748c2ecf20Sopenharmony_ci	err = copy_mem_in(&u.b[i], ea, nb, regs);
3758c2ecf20Sopenharmony_ci	if (!err)
3768c2ecf20Sopenharmony_ci		*dest = u.ul;
3778c2ecf20Sopenharmony_ci	return err;
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci/*
3818c2ecf20Sopenharmony_ci * Read memory at address ea for nb bytes, return 0 for success
3828c2ecf20Sopenharmony_ci * or -EFAULT if an error occurred.  N.B. nb must be 1, 2, 4 or 8.
3838c2ecf20Sopenharmony_ci * If nb < sizeof(long), the result is right-justified on BE systems.
3848c2ecf20Sopenharmony_ci */
3858c2ecf20Sopenharmony_cistatic int read_mem(unsigned long *dest, unsigned long ea, int nb,
3868c2ecf20Sopenharmony_ci			      struct pt_regs *regs)
3878c2ecf20Sopenharmony_ci{
3888c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea, nb))
3898c2ecf20Sopenharmony_ci		return -EFAULT;
3908c2ecf20Sopenharmony_ci	if ((ea & (nb - 1)) == 0)
3918c2ecf20Sopenharmony_ci		return read_mem_aligned(dest, ea, nb, regs);
3928c2ecf20Sopenharmony_ci	return read_mem_unaligned(dest, ea, nb, regs);
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(read_mem);
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_cistatic nokprobe_inline int write_mem_aligned(unsigned long val,
3978c2ecf20Sopenharmony_ci					     unsigned long ea, int nb,
3988c2ecf20Sopenharmony_ci					     struct pt_regs *regs)
3998c2ecf20Sopenharmony_ci{
4008c2ecf20Sopenharmony_ci	int err = 0;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	switch (nb) {
4038c2ecf20Sopenharmony_ci	case 1:
4048c2ecf20Sopenharmony_ci		err = __put_user(val, (unsigned char __user *) ea);
4058c2ecf20Sopenharmony_ci		break;
4068c2ecf20Sopenharmony_ci	case 2:
4078c2ecf20Sopenharmony_ci		err = __put_user(val, (unsigned short __user *) ea);
4088c2ecf20Sopenharmony_ci		break;
4098c2ecf20Sopenharmony_ci	case 4:
4108c2ecf20Sopenharmony_ci		err = __put_user(val, (unsigned int __user *) ea);
4118c2ecf20Sopenharmony_ci		break;
4128c2ecf20Sopenharmony_ci#ifdef __powerpc64__
4138c2ecf20Sopenharmony_ci	case 8:
4148c2ecf20Sopenharmony_ci		err = __put_user(val, (unsigned long __user *) ea);
4158c2ecf20Sopenharmony_ci		break;
4168c2ecf20Sopenharmony_ci#endif
4178c2ecf20Sopenharmony_ci	}
4188c2ecf20Sopenharmony_ci	if (err)
4198c2ecf20Sopenharmony_ci		regs->dar = ea;
4208c2ecf20Sopenharmony_ci	return err;
4218c2ecf20Sopenharmony_ci}
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci/*
4248c2ecf20Sopenharmony_ci * Copy from a buffer to userspace, using the largest possible
4258c2ecf20Sopenharmony_ci * aligned accesses, up to sizeof(long).
4268c2ecf20Sopenharmony_ci */
4278c2ecf20Sopenharmony_cistatic nokprobe_inline int copy_mem_out(u8 *dest, unsigned long ea, int nb,
4288c2ecf20Sopenharmony_ci					struct pt_regs *regs)
4298c2ecf20Sopenharmony_ci{
4308c2ecf20Sopenharmony_ci	int err = 0;
4318c2ecf20Sopenharmony_ci	int c;
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	for (; nb > 0; nb -= c) {
4348c2ecf20Sopenharmony_ci		c = max_align(ea);
4358c2ecf20Sopenharmony_ci		if (c > nb)
4368c2ecf20Sopenharmony_ci			c = max_align(nb);
4378c2ecf20Sopenharmony_ci		switch (c) {
4388c2ecf20Sopenharmony_ci		case 1:
4398c2ecf20Sopenharmony_ci			err = __put_user(*dest, (unsigned char __user *) ea);
4408c2ecf20Sopenharmony_ci			break;
4418c2ecf20Sopenharmony_ci		case 2:
4428c2ecf20Sopenharmony_ci			err = __put_user(*(u16 *)dest,
4438c2ecf20Sopenharmony_ci					 (unsigned short __user *) ea);
4448c2ecf20Sopenharmony_ci			break;
4458c2ecf20Sopenharmony_ci		case 4:
4468c2ecf20Sopenharmony_ci			err = __put_user(*(u32 *)dest,
4478c2ecf20Sopenharmony_ci					 (unsigned int __user *) ea);
4488c2ecf20Sopenharmony_ci			break;
4498c2ecf20Sopenharmony_ci#ifdef __powerpc64__
4508c2ecf20Sopenharmony_ci		case 8:
4518c2ecf20Sopenharmony_ci			err = __put_user(*(unsigned long *)dest,
4528c2ecf20Sopenharmony_ci					 (unsigned long __user *) ea);
4538c2ecf20Sopenharmony_ci			break;
4548c2ecf20Sopenharmony_ci#endif
4558c2ecf20Sopenharmony_ci		}
4568c2ecf20Sopenharmony_ci		if (err) {
4578c2ecf20Sopenharmony_ci			regs->dar = ea;
4588c2ecf20Sopenharmony_ci			return err;
4598c2ecf20Sopenharmony_ci		}
4608c2ecf20Sopenharmony_ci		dest += c;
4618c2ecf20Sopenharmony_ci		ea += c;
4628c2ecf20Sopenharmony_ci	}
4638c2ecf20Sopenharmony_ci	return 0;
4648c2ecf20Sopenharmony_ci}
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_cistatic nokprobe_inline int write_mem_unaligned(unsigned long val,
4678c2ecf20Sopenharmony_ci					       unsigned long ea, int nb,
4688c2ecf20Sopenharmony_ci					       struct pt_regs *regs)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	union {
4718c2ecf20Sopenharmony_ci		unsigned long ul;
4728c2ecf20Sopenharmony_ci		u8 b[sizeof(unsigned long)];
4738c2ecf20Sopenharmony_ci	} u;
4748c2ecf20Sopenharmony_ci	int i;
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_ci	u.ul = val;
4778c2ecf20Sopenharmony_ci	i = IS_BE ? sizeof(unsigned long) - nb : 0;
4788c2ecf20Sopenharmony_ci	return copy_mem_out(&u.b[i], ea, nb, regs);
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/*
4828c2ecf20Sopenharmony_ci * Write memory at address ea for nb bytes, return 0 for success
4838c2ecf20Sopenharmony_ci * or -EFAULT if an error occurred.  N.B. nb must be 1, 2, 4 or 8.
4848c2ecf20Sopenharmony_ci */
4858c2ecf20Sopenharmony_cistatic int write_mem(unsigned long val, unsigned long ea, int nb,
4868c2ecf20Sopenharmony_ci			       struct pt_regs *regs)
4878c2ecf20Sopenharmony_ci{
4888c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea, nb))
4898c2ecf20Sopenharmony_ci		return -EFAULT;
4908c2ecf20Sopenharmony_ci	if ((ea & (nb - 1)) == 0)
4918c2ecf20Sopenharmony_ci		return write_mem_aligned(val, ea, nb, regs);
4928c2ecf20Sopenharmony_ci	return write_mem_unaligned(val, ea, nb, regs);
4938c2ecf20Sopenharmony_ci}
4948c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(write_mem);
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_FPU
4978c2ecf20Sopenharmony_ci/*
4988c2ecf20Sopenharmony_ci * These access either the real FP register or the image in the
4998c2ecf20Sopenharmony_ci * thread_struct, depending on regs->msr & MSR_FP.
5008c2ecf20Sopenharmony_ci */
5018c2ecf20Sopenharmony_cistatic int do_fp_load(struct instruction_op *op, unsigned long ea,
5028c2ecf20Sopenharmony_ci		      struct pt_regs *regs, bool cross_endian)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	int err, rn, nb;
5058c2ecf20Sopenharmony_ci	union {
5068c2ecf20Sopenharmony_ci		int i;
5078c2ecf20Sopenharmony_ci		unsigned int u;
5088c2ecf20Sopenharmony_ci		float f;
5098c2ecf20Sopenharmony_ci		double d[2];
5108c2ecf20Sopenharmony_ci		unsigned long l[2];
5118c2ecf20Sopenharmony_ci		u8 b[2 * sizeof(double)];
5128c2ecf20Sopenharmony_ci	} u;
5138c2ecf20Sopenharmony_ci
5148c2ecf20Sopenharmony_ci	nb = GETSIZE(op->type);
5158c2ecf20Sopenharmony_ci	if (nb > sizeof(u))
5168c2ecf20Sopenharmony_ci		return -EINVAL;
5178c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea, nb))
5188c2ecf20Sopenharmony_ci		return -EFAULT;
5198c2ecf20Sopenharmony_ci	rn = op->reg;
5208c2ecf20Sopenharmony_ci	err = copy_mem_in(u.b, ea, nb, regs);
5218c2ecf20Sopenharmony_ci	if (err)
5228c2ecf20Sopenharmony_ci		return err;
5238c2ecf20Sopenharmony_ci	if (unlikely(cross_endian)) {
5248c2ecf20Sopenharmony_ci		do_byte_reverse(u.b, min(nb, 8));
5258c2ecf20Sopenharmony_ci		if (nb == 16)
5268c2ecf20Sopenharmony_ci			do_byte_reverse(&u.b[8], 8);
5278c2ecf20Sopenharmony_ci	}
5288c2ecf20Sopenharmony_ci	preempt_disable();
5298c2ecf20Sopenharmony_ci	if (nb == 4) {
5308c2ecf20Sopenharmony_ci		if (op->type & FPCONV)
5318c2ecf20Sopenharmony_ci			conv_sp_to_dp(&u.f, &u.d[0]);
5328c2ecf20Sopenharmony_ci		else if (op->type & SIGNEXT)
5338c2ecf20Sopenharmony_ci			u.l[0] = u.i;
5348c2ecf20Sopenharmony_ci		else
5358c2ecf20Sopenharmony_ci			u.l[0] = u.u;
5368c2ecf20Sopenharmony_ci	}
5378c2ecf20Sopenharmony_ci	if (regs->msr & MSR_FP)
5388c2ecf20Sopenharmony_ci		put_fpr(rn, &u.d[0]);
5398c2ecf20Sopenharmony_ci	else
5408c2ecf20Sopenharmony_ci		current->thread.TS_FPR(rn) = u.l[0];
5418c2ecf20Sopenharmony_ci	if (nb == 16) {
5428c2ecf20Sopenharmony_ci		/* lfdp */
5438c2ecf20Sopenharmony_ci		rn |= 1;
5448c2ecf20Sopenharmony_ci		if (regs->msr & MSR_FP)
5458c2ecf20Sopenharmony_ci			put_fpr(rn, &u.d[1]);
5468c2ecf20Sopenharmony_ci		else
5478c2ecf20Sopenharmony_ci			current->thread.TS_FPR(rn) = u.l[1];
5488c2ecf20Sopenharmony_ci	}
5498c2ecf20Sopenharmony_ci	preempt_enable();
5508c2ecf20Sopenharmony_ci	return 0;
5518c2ecf20Sopenharmony_ci}
5528c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(do_fp_load);
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_cistatic int do_fp_store(struct instruction_op *op, unsigned long ea,
5558c2ecf20Sopenharmony_ci		       struct pt_regs *regs, bool cross_endian)
5568c2ecf20Sopenharmony_ci{
5578c2ecf20Sopenharmony_ci	int rn, nb;
5588c2ecf20Sopenharmony_ci	union {
5598c2ecf20Sopenharmony_ci		unsigned int u;
5608c2ecf20Sopenharmony_ci		float f;
5618c2ecf20Sopenharmony_ci		double d[2];
5628c2ecf20Sopenharmony_ci		unsigned long l[2];
5638c2ecf20Sopenharmony_ci		u8 b[2 * sizeof(double)];
5648c2ecf20Sopenharmony_ci	} u;
5658c2ecf20Sopenharmony_ci
5668c2ecf20Sopenharmony_ci	nb = GETSIZE(op->type);
5678c2ecf20Sopenharmony_ci	if (nb > sizeof(u))
5688c2ecf20Sopenharmony_ci		return -EINVAL;
5698c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea, nb))
5708c2ecf20Sopenharmony_ci		return -EFAULT;
5718c2ecf20Sopenharmony_ci	rn = op->reg;
5728c2ecf20Sopenharmony_ci	preempt_disable();
5738c2ecf20Sopenharmony_ci	if (regs->msr & MSR_FP)
5748c2ecf20Sopenharmony_ci		get_fpr(rn, &u.d[0]);
5758c2ecf20Sopenharmony_ci	else
5768c2ecf20Sopenharmony_ci		u.l[0] = current->thread.TS_FPR(rn);
5778c2ecf20Sopenharmony_ci	if (nb == 4) {
5788c2ecf20Sopenharmony_ci		if (op->type & FPCONV)
5798c2ecf20Sopenharmony_ci			conv_dp_to_sp(&u.d[0], &u.f);
5808c2ecf20Sopenharmony_ci		else
5818c2ecf20Sopenharmony_ci			u.u = u.l[0];
5828c2ecf20Sopenharmony_ci	}
5838c2ecf20Sopenharmony_ci	if (nb == 16) {
5848c2ecf20Sopenharmony_ci		rn |= 1;
5858c2ecf20Sopenharmony_ci		if (regs->msr & MSR_FP)
5868c2ecf20Sopenharmony_ci			get_fpr(rn, &u.d[1]);
5878c2ecf20Sopenharmony_ci		else
5888c2ecf20Sopenharmony_ci			u.l[1] = current->thread.TS_FPR(rn);
5898c2ecf20Sopenharmony_ci	}
5908c2ecf20Sopenharmony_ci	preempt_enable();
5918c2ecf20Sopenharmony_ci	if (unlikely(cross_endian)) {
5928c2ecf20Sopenharmony_ci		do_byte_reverse(u.b, min(nb, 8));
5938c2ecf20Sopenharmony_ci		if (nb == 16)
5948c2ecf20Sopenharmony_ci			do_byte_reverse(&u.b[8], 8);
5958c2ecf20Sopenharmony_ci	}
5968c2ecf20Sopenharmony_ci	return copy_mem_out(u.b, ea, nb, regs);
5978c2ecf20Sopenharmony_ci}
5988c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(do_fp_store);
5998c2ecf20Sopenharmony_ci#endif
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC
6028c2ecf20Sopenharmony_ci/* For Altivec/VMX, no need to worry about alignment */
6038c2ecf20Sopenharmony_cistatic nokprobe_inline int do_vec_load(int rn, unsigned long ea,
6048c2ecf20Sopenharmony_ci				       int size, struct pt_regs *regs,
6058c2ecf20Sopenharmony_ci				       bool cross_endian)
6068c2ecf20Sopenharmony_ci{
6078c2ecf20Sopenharmony_ci	int err;
6088c2ecf20Sopenharmony_ci	union {
6098c2ecf20Sopenharmony_ci		__vector128 v;
6108c2ecf20Sopenharmony_ci		u8 b[sizeof(__vector128)];
6118c2ecf20Sopenharmony_ci	} u = {};
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	if (size > sizeof(u))
6148c2ecf20Sopenharmony_ci		return -EINVAL;
6158c2ecf20Sopenharmony_ci
6168c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea & ~0xfUL, 16))
6178c2ecf20Sopenharmony_ci		return -EFAULT;
6188c2ecf20Sopenharmony_ci	/* align to multiple of size */
6198c2ecf20Sopenharmony_ci	ea &= ~(size - 1);
6208c2ecf20Sopenharmony_ci	err = copy_mem_in(&u.b[ea & 0xf], ea, size, regs);
6218c2ecf20Sopenharmony_ci	if (err)
6228c2ecf20Sopenharmony_ci		return err;
6238c2ecf20Sopenharmony_ci	if (unlikely(cross_endian))
6248c2ecf20Sopenharmony_ci		do_byte_reverse(&u.b[ea & 0xf], size);
6258c2ecf20Sopenharmony_ci	preempt_disable();
6268c2ecf20Sopenharmony_ci	if (regs->msr & MSR_VEC)
6278c2ecf20Sopenharmony_ci		put_vr(rn, &u.v);
6288c2ecf20Sopenharmony_ci	else
6298c2ecf20Sopenharmony_ci		current->thread.vr_state.vr[rn] = u.v;
6308c2ecf20Sopenharmony_ci	preempt_enable();
6318c2ecf20Sopenharmony_ci	return 0;
6328c2ecf20Sopenharmony_ci}
6338c2ecf20Sopenharmony_ci
6348c2ecf20Sopenharmony_cistatic nokprobe_inline int do_vec_store(int rn, unsigned long ea,
6358c2ecf20Sopenharmony_ci					int size, struct pt_regs *regs,
6368c2ecf20Sopenharmony_ci					bool cross_endian)
6378c2ecf20Sopenharmony_ci{
6388c2ecf20Sopenharmony_ci	union {
6398c2ecf20Sopenharmony_ci		__vector128 v;
6408c2ecf20Sopenharmony_ci		u8 b[sizeof(__vector128)];
6418c2ecf20Sopenharmony_ci	} u;
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ci	if (size > sizeof(u))
6448c2ecf20Sopenharmony_ci		return -EINVAL;
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea & ~0xfUL, 16))
6478c2ecf20Sopenharmony_ci		return -EFAULT;
6488c2ecf20Sopenharmony_ci	/* align to multiple of size */
6498c2ecf20Sopenharmony_ci	ea &= ~(size - 1);
6508c2ecf20Sopenharmony_ci
6518c2ecf20Sopenharmony_ci	preempt_disable();
6528c2ecf20Sopenharmony_ci	if (regs->msr & MSR_VEC)
6538c2ecf20Sopenharmony_ci		get_vr(rn, &u.v);
6548c2ecf20Sopenharmony_ci	else
6558c2ecf20Sopenharmony_ci		u.v = current->thread.vr_state.vr[rn];
6568c2ecf20Sopenharmony_ci	preempt_enable();
6578c2ecf20Sopenharmony_ci	if (unlikely(cross_endian))
6588c2ecf20Sopenharmony_ci		do_byte_reverse(&u.b[ea & 0xf], size);
6598c2ecf20Sopenharmony_ci	return copy_mem_out(&u.b[ea & 0xf], ea, size, regs);
6608c2ecf20Sopenharmony_ci}
6618c2ecf20Sopenharmony_ci#endif /* CONFIG_ALTIVEC */
6628c2ecf20Sopenharmony_ci
6638c2ecf20Sopenharmony_ci#ifdef __powerpc64__
6648c2ecf20Sopenharmony_cistatic nokprobe_inline int emulate_lq(struct pt_regs *regs, unsigned long ea,
6658c2ecf20Sopenharmony_ci				      int reg, bool cross_endian)
6668c2ecf20Sopenharmony_ci{
6678c2ecf20Sopenharmony_ci	int err;
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea, 16))
6708c2ecf20Sopenharmony_ci		return -EFAULT;
6718c2ecf20Sopenharmony_ci	/* if aligned, should be atomic */
6728c2ecf20Sopenharmony_ci	if ((ea & 0xf) == 0) {
6738c2ecf20Sopenharmony_ci		err = do_lq(ea, &regs->gpr[reg]);
6748c2ecf20Sopenharmony_ci	} else {
6758c2ecf20Sopenharmony_ci		err = read_mem(&regs->gpr[reg + IS_LE], ea, 8, regs);
6768c2ecf20Sopenharmony_ci		if (!err)
6778c2ecf20Sopenharmony_ci			err = read_mem(&regs->gpr[reg + IS_BE], ea + 8, 8, regs);
6788c2ecf20Sopenharmony_ci	}
6798c2ecf20Sopenharmony_ci	if (!err && unlikely(cross_endian))
6808c2ecf20Sopenharmony_ci		do_byte_reverse(&regs->gpr[reg], 16);
6818c2ecf20Sopenharmony_ci	return err;
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_cistatic nokprobe_inline int emulate_stq(struct pt_regs *regs, unsigned long ea,
6858c2ecf20Sopenharmony_ci				       int reg, bool cross_endian)
6868c2ecf20Sopenharmony_ci{
6878c2ecf20Sopenharmony_ci	int err;
6888c2ecf20Sopenharmony_ci	unsigned long vals[2];
6898c2ecf20Sopenharmony_ci
6908c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea, 16))
6918c2ecf20Sopenharmony_ci		return -EFAULT;
6928c2ecf20Sopenharmony_ci	vals[0] = regs->gpr[reg];
6938c2ecf20Sopenharmony_ci	vals[1] = regs->gpr[reg + 1];
6948c2ecf20Sopenharmony_ci	if (unlikely(cross_endian))
6958c2ecf20Sopenharmony_ci		do_byte_reverse(vals, 16);
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci	/* if aligned, should be atomic */
6988c2ecf20Sopenharmony_ci	if ((ea & 0xf) == 0)
6998c2ecf20Sopenharmony_ci		return do_stq(ea, vals[0], vals[1]);
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci	err = write_mem(vals[IS_LE], ea, 8, regs);
7028c2ecf20Sopenharmony_ci	if (!err)
7038c2ecf20Sopenharmony_ci		err = write_mem(vals[IS_BE], ea + 8, 8, regs);
7048c2ecf20Sopenharmony_ci	return err;
7058c2ecf20Sopenharmony_ci}
7068c2ecf20Sopenharmony_ci#endif /* __powerpc64 */
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX
7098c2ecf20Sopenharmony_civoid emulate_vsx_load(struct instruction_op *op, union vsx_reg *reg,
7108c2ecf20Sopenharmony_ci		      const void *mem, bool rev)
7118c2ecf20Sopenharmony_ci{
7128c2ecf20Sopenharmony_ci	int size, read_size;
7138c2ecf20Sopenharmony_ci	int i, j;
7148c2ecf20Sopenharmony_ci	const unsigned int *wp;
7158c2ecf20Sopenharmony_ci	const unsigned short *hp;
7168c2ecf20Sopenharmony_ci	const unsigned char *bp;
7178c2ecf20Sopenharmony_ci
7188c2ecf20Sopenharmony_ci	size = GETSIZE(op->type);
7198c2ecf20Sopenharmony_ci	reg->d[0] = reg->d[1] = 0;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	switch (op->element_size) {
7228c2ecf20Sopenharmony_ci	case 16:
7238c2ecf20Sopenharmony_ci		/* whole vector; lxv[x] or lxvl[l] */
7248c2ecf20Sopenharmony_ci		if (size == 0)
7258c2ecf20Sopenharmony_ci			break;
7268c2ecf20Sopenharmony_ci		memcpy(reg, mem, size);
7278c2ecf20Sopenharmony_ci		if (IS_LE && (op->vsx_flags & VSX_LDLEFT))
7288c2ecf20Sopenharmony_ci			rev = !rev;
7298c2ecf20Sopenharmony_ci		if (rev)
7308c2ecf20Sopenharmony_ci			do_byte_reverse(reg, 16);
7318c2ecf20Sopenharmony_ci		break;
7328c2ecf20Sopenharmony_ci	case 8:
7338c2ecf20Sopenharmony_ci		/* scalar loads, lxvd2x, lxvdsx */
7348c2ecf20Sopenharmony_ci		read_size = (size >= 8) ? 8 : size;
7358c2ecf20Sopenharmony_ci		i = IS_LE ? 8 : 8 - read_size;
7368c2ecf20Sopenharmony_ci		memcpy(&reg->b[i], mem, read_size);
7378c2ecf20Sopenharmony_ci		if (rev)
7388c2ecf20Sopenharmony_ci			do_byte_reverse(&reg->b[i], 8);
7398c2ecf20Sopenharmony_ci		if (size < 8) {
7408c2ecf20Sopenharmony_ci			if (op->type & SIGNEXT) {
7418c2ecf20Sopenharmony_ci				/* size == 4 is the only case here */
7428c2ecf20Sopenharmony_ci				reg->d[IS_LE] = (signed int) reg->d[IS_LE];
7438c2ecf20Sopenharmony_ci			} else if (op->vsx_flags & VSX_FPCONV) {
7448c2ecf20Sopenharmony_ci				preempt_disable();
7458c2ecf20Sopenharmony_ci				conv_sp_to_dp(&reg->fp[1 + IS_LE],
7468c2ecf20Sopenharmony_ci					      &reg->dp[IS_LE]);
7478c2ecf20Sopenharmony_ci				preempt_enable();
7488c2ecf20Sopenharmony_ci			}
7498c2ecf20Sopenharmony_ci		} else {
7508c2ecf20Sopenharmony_ci			if (size == 16) {
7518c2ecf20Sopenharmony_ci				unsigned long v = *(unsigned long *)(mem + 8);
7528c2ecf20Sopenharmony_ci				reg->d[IS_BE] = !rev ? v : byterev_8(v);
7538c2ecf20Sopenharmony_ci			} else if (op->vsx_flags & VSX_SPLAT)
7548c2ecf20Sopenharmony_ci				reg->d[IS_BE] = reg->d[IS_LE];
7558c2ecf20Sopenharmony_ci		}
7568c2ecf20Sopenharmony_ci		break;
7578c2ecf20Sopenharmony_ci	case 4:
7588c2ecf20Sopenharmony_ci		/* lxvw4x, lxvwsx */
7598c2ecf20Sopenharmony_ci		wp = mem;
7608c2ecf20Sopenharmony_ci		for (j = 0; j < size / 4; ++j) {
7618c2ecf20Sopenharmony_ci			i = IS_LE ? 3 - j : j;
7628c2ecf20Sopenharmony_ci			reg->w[i] = !rev ? *wp++ : byterev_4(*wp++);
7638c2ecf20Sopenharmony_ci		}
7648c2ecf20Sopenharmony_ci		if (op->vsx_flags & VSX_SPLAT) {
7658c2ecf20Sopenharmony_ci			u32 val = reg->w[IS_LE ? 3 : 0];
7668c2ecf20Sopenharmony_ci			for (; j < 4; ++j) {
7678c2ecf20Sopenharmony_ci				i = IS_LE ? 3 - j : j;
7688c2ecf20Sopenharmony_ci				reg->w[i] = val;
7698c2ecf20Sopenharmony_ci			}
7708c2ecf20Sopenharmony_ci		}
7718c2ecf20Sopenharmony_ci		break;
7728c2ecf20Sopenharmony_ci	case 2:
7738c2ecf20Sopenharmony_ci		/* lxvh8x */
7748c2ecf20Sopenharmony_ci		hp = mem;
7758c2ecf20Sopenharmony_ci		for (j = 0; j < size / 2; ++j) {
7768c2ecf20Sopenharmony_ci			i = IS_LE ? 7 - j : j;
7778c2ecf20Sopenharmony_ci			reg->h[i] = !rev ? *hp++ : byterev_2(*hp++);
7788c2ecf20Sopenharmony_ci		}
7798c2ecf20Sopenharmony_ci		break;
7808c2ecf20Sopenharmony_ci	case 1:
7818c2ecf20Sopenharmony_ci		/* lxvb16x */
7828c2ecf20Sopenharmony_ci		bp = mem;
7838c2ecf20Sopenharmony_ci		for (j = 0; j < size; ++j) {
7848c2ecf20Sopenharmony_ci			i = IS_LE ? 15 - j : j;
7858c2ecf20Sopenharmony_ci			reg->b[i] = *bp++;
7868c2ecf20Sopenharmony_ci		}
7878c2ecf20Sopenharmony_ci		break;
7888c2ecf20Sopenharmony_ci	}
7898c2ecf20Sopenharmony_ci}
7908c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(emulate_vsx_load);
7918c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(emulate_vsx_load);
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_civoid emulate_vsx_store(struct instruction_op *op, const union vsx_reg *reg,
7948c2ecf20Sopenharmony_ci		       void *mem, bool rev)
7958c2ecf20Sopenharmony_ci{
7968c2ecf20Sopenharmony_ci	int size, write_size;
7978c2ecf20Sopenharmony_ci	int i, j;
7988c2ecf20Sopenharmony_ci	union vsx_reg buf;
7998c2ecf20Sopenharmony_ci	unsigned int *wp;
8008c2ecf20Sopenharmony_ci	unsigned short *hp;
8018c2ecf20Sopenharmony_ci	unsigned char *bp;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	size = GETSIZE(op->type);
8048c2ecf20Sopenharmony_ci
8058c2ecf20Sopenharmony_ci	switch (op->element_size) {
8068c2ecf20Sopenharmony_ci	case 16:
8078c2ecf20Sopenharmony_ci		/* stxv, stxvx, stxvl, stxvll */
8088c2ecf20Sopenharmony_ci		if (size == 0)
8098c2ecf20Sopenharmony_ci			break;
8108c2ecf20Sopenharmony_ci		if (IS_LE && (op->vsx_flags & VSX_LDLEFT))
8118c2ecf20Sopenharmony_ci			rev = !rev;
8128c2ecf20Sopenharmony_ci		if (rev) {
8138c2ecf20Sopenharmony_ci			/* reverse 16 bytes */
8148c2ecf20Sopenharmony_ci			buf.d[0] = byterev_8(reg->d[1]);
8158c2ecf20Sopenharmony_ci			buf.d[1] = byterev_8(reg->d[0]);
8168c2ecf20Sopenharmony_ci			reg = &buf;
8178c2ecf20Sopenharmony_ci		}
8188c2ecf20Sopenharmony_ci		memcpy(mem, reg, size);
8198c2ecf20Sopenharmony_ci		break;
8208c2ecf20Sopenharmony_ci	case 8:
8218c2ecf20Sopenharmony_ci		/* scalar stores, stxvd2x */
8228c2ecf20Sopenharmony_ci		write_size = (size >= 8) ? 8 : size;
8238c2ecf20Sopenharmony_ci		i = IS_LE ? 8 : 8 - write_size;
8248c2ecf20Sopenharmony_ci		if (size < 8 && op->vsx_flags & VSX_FPCONV) {
8258c2ecf20Sopenharmony_ci			buf.d[0] = buf.d[1] = 0;
8268c2ecf20Sopenharmony_ci			preempt_disable();
8278c2ecf20Sopenharmony_ci			conv_dp_to_sp(&reg->dp[IS_LE], &buf.fp[1 + IS_LE]);
8288c2ecf20Sopenharmony_ci			preempt_enable();
8298c2ecf20Sopenharmony_ci			reg = &buf;
8308c2ecf20Sopenharmony_ci		}
8318c2ecf20Sopenharmony_ci		memcpy(mem, &reg->b[i], write_size);
8328c2ecf20Sopenharmony_ci		if (size == 16)
8338c2ecf20Sopenharmony_ci			memcpy(mem + 8, &reg->d[IS_BE], 8);
8348c2ecf20Sopenharmony_ci		if (unlikely(rev)) {
8358c2ecf20Sopenharmony_ci			do_byte_reverse(mem, write_size);
8368c2ecf20Sopenharmony_ci			if (size == 16)
8378c2ecf20Sopenharmony_ci				do_byte_reverse(mem + 8, 8);
8388c2ecf20Sopenharmony_ci		}
8398c2ecf20Sopenharmony_ci		break;
8408c2ecf20Sopenharmony_ci	case 4:
8418c2ecf20Sopenharmony_ci		/* stxvw4x */
8428c2ecf20Sopenharmony_ci		wp = mem;
8438c2ecf20Sopenharmony_ci		for (j = 0; j < size / 4; ++j) {
8448c2ecf20Sopenharmony_ci			i = IS_LE ? 3 - j : j;
8458c2ecf20Sopenharmony_ci			*wp++ = !rev ? reg->w[i] : byterev_4(reg->w[i]);
8468c2ecf20Sopenharmony_ci		}
8478c2ecf20Sopenharmony_ci		break;
8488c2ecf20Sopenharmony_ci	case 2:
8498c2ecf20Sopenharmony_ci		/* stxvh8x */
8508c2ecf20Sopenharmony_ci		hp = mem;
8518c2ecf20Sopenharmony_ci		for (j = 0; j < size / 2; ++j) {
8528c2ecf20Sopenharmony_ci			i = IS_LE ? 7 - j : j;
8538c2ecf20Sopenharmony_ci			*hp++ = !rev ? reg->h[i] : byterev_2(reg->h[i]);
8548c2ecf20Sopenharmony_ci		}
8558c2ecf20Sopenharmony_ci		break;
8568c2ecf20Sopenharmony_ci	case 1:
8578c2ecf20Sopenharmony_ci		/* stvxb16x */
8588c2ecf20Sopenharmony_ci		bp = mem;
8598c2ecf20Sopenharmony_ci		for (j = 0; j < size; ++j) {
8608c2ecf20Sopenharmony_ci			i = IS_LE ? 15 - j : j;
8618c2ecf20Sopenharmony_ci			*bp++ = reg->b[i];
8628c2ecf20Sopenharmony_ci		}
8638c2ecf20Sopenharmony_ci		break;
8648c2ecf20Sopenharmony_ci	}
8658c2ecf20Sopenharmony_ci}
8668c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(emulate_vsx_store);
8678c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(emulate_vsx_store);
8688c2ecf20Sopenharmony_ci
8698c2ecf20Sopenharmony_cistatic nokprobe_inline int do_vsx_load(struct instruction_op *op,
8708c2ecf20Sopenharmony_ci				       unsigned long ea, struct pt_regs *regs,
8718c2ecf20Sopenharmony_ci				       bool cross_endian)
8728c2ecf20Sopenharmony_ci{
8738c2ecf20Sopenharmony_ci	int reg = op->reg;
8748c2ecf20Sopenharmony_ci	u8 mem[16];
8758c2ecf20Sopenharmony_ci	union vsx_reg buf;
8768c2ecf20Sopenharmony_ci	int size = GETSIZE(op->type);
8778c2ecf20Sopenharmony_ci
8788c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea, size) || copy_mem_in(mem, ea, size, regs))
8798c2ecf20Sopenharmony_ci		return -EFAULT;
8808c2ecf20Sopenharmony_ci
8818c2ecf20Sopenharmony_ci	emulate_vsx_load(op, &buf, mem, cross_endian);
8828c2ecf20Sopenharmony_ci	preempt_disable();
8838c2ecf20Sopenharmony_ci	if (reg < 32) {
8848c2ecf20Sopenharmony_ci		/* FP regs + extensions */
8858c2ecf20Sopenharmony_ci		if (regs->msr & MSR_FP) {
8868c2ecf20Sopenharmony_ci			load_vsrn(reg, &buf);
8878c2ecf20Sopenharmony_ci		} else {
8888c2ecf20Sopenharmony_ci			current->thread.fp_state.fpr[reg][0] = buf.d[0];
8898c2ecf20Sopenharmony_ci			current->thread.fp_state.fpr[reg][1] = buf.d[1];
8908c2ecf20Sopenharmony_ci		}
8918c2ecf20Sopenharmony_ci	} else {
8928c2ecf20Sopenharmony_ci		if (regs->msr & MSR_VEC)
8938c2ecf20Sopenharmony_ci			load_vsrn(reg, &buf);
8948c2ecf20Sopenharmony_ci		else
8958c2ecf20Sopenharmony_ci			current->thread.vr_state.vr[reg - 32] = buf.v;
8968c2ecf20Sopenharmony_ci	}
8978c2ecf20Sopenharmony_ci	preempt_enable();
8988c2ecf20Sopenharmony_ci	return 0;
8998c2ecf20Sopenharmony_ci}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_cistatic nokprobe_inline int do_vsx_store(struct instruction_op *op,
9028c2ecf20Sopenharmony_ci					unsigned long ea, struct pt_regs *regs,
9038c2ecf20Sopenharmony_ci					bool cross_endian)
9048c2ecf20Sopenharmony_ci{
9058c2ecf20Sopenharmony_ci	int reg = op->reg;
9068c2ecf20Sopenharmony_ci	u8 mem[16];
9078c2ecf20Sopenharmony_ci	union vsx_reg buf;
9088c2ecf20Sopenharmony_ci	int size = GETSIZE(op->type);
9098c2ecf20Sopenharmony_ci
9108c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea, size))
9118c2ecf20Sopenharmony_ci		return -EFAULT;
9128c2ecf20Sopenharmony_ci
9138c2ecf20Sopenharmony_ci	preempt_disable();
9148c2ecf20Sopenharmony_ci	if (reg < 32) {
9158c2ecf20Sopenharmony_ci		/* FP regs + extensions */
9168c2ecf20Sopenharmony_ci		if (regs->msr & MSR_FP) {
9178c2ecf20Sopenharmony_ci			store_vsrn(reg, &buf);
9188c2ecf20Sopenharmony_ci		} else {
9198c2ecf20Sopenharmony_ci			buf.d[0] = current->thread.fp_state.fpr[reg][0];
9208c2ecf20Sopenharmony_ci			buf.d[1] = current->thread.fp_state.fpr[reg][1];
9218c2ecf20Sopenharmony_ci		}
9228c2ecf20Sopenharmony_ci	} else {
9238c2ecf20Sopenharmony_ci		if (regs->msr & MSR_VEC)
9248c2ecf20Sopenharmony_ci			store_vsrn(reg, &buf);
9258c2ecf20Sopenharmony_ci		else
9268c2ecf20Sopenharmony_ci			buf.v = current->thread.vr_state.vr[reg - 32];
9278c2ecf20Sopenharmony_ci	}
9288c2ecf20Sopenharmony_ci	preempt_enable();
9298c2ecf20Sopenharmony_ci	emulate_vsx_store(op, &buf, mem, cross_endian);
9308c2ecf20Sopenharmony_ci	return  copy_mem_out(mem, ea, size, regs);
9318c2ecf20Sopenharmony_ci}
9328c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */
9338c2ecf20Sopenharmony_ci
9348c2ecf20Sopenharmony_ciint emulate_dcbz(unsigned long ea, struct pt_regs *regs)
9358c2ecf20Sopenharmony_ci{
9368c2ecf20Sopenharmony_ci	int err;
9378c2ecf20Sopenharmony_ci	unsigned long i, size;
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci#ifdef __powerpc64__
9408c2ecf20Sopenharmony_ci	size = ppc64_caches.l1d.block_size;
9418c2ecf20Sopenharmony_ci	if (!(regs->msr & MSR_64BIT))
9428c2ecf20Sopenharmony_ci		ea &= 0xffffffffUL;
9438c2ecf20Sopenharmony_ci#else
9448c2ecf20Sopenharmony_ci	size = L1_CACHE_BYTES;
9458c2ecf20Sopenharmony_ci#endif
9468c2ecf20Sopenharmony_ci	ea &= ~(size - 1);
9478c2ecf20Sopenharmony_ci	if (!address_ok(regs, ea, size))
9488c2ecf20Sopenharmony_ci		return -EFAULT;
9498c2ecf20Sopenharmony_ci	for (i = 0; i < size; i += sizeof(long)) {
9508c2ecf20Sopenharmony_ci		err = __put_user(0, (unsigned long __user *) (ea + i));
9518c2ecf20Sopenharmony_ci		if (err) {
9528c2ecf20Sopenharmony_ci			regs->dar = ea;
9538c2ecf20Sopenharmony_ci			return err;
9548c2ecf20Sopenharmony_ci		}
9558c2ecf20Sopenharmony_ci	}
9568c2ecf20Sopenharmony_ci	return 0;
9578c2ecf20Sopenharmony_ci}
9588c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(emulate_dcbz);
9598c2ecf20Sopenharmony_ci
9608c2ecf20Sopenharmony_ci#define __put_user_asmx(x, addr, err, op, cr)		\
9618c2ecf20Sopenharmony_ci	__asm__ __volatile__(				\
9628c2ecf20Sopenharmony_ci		".machine push\n"			\
9638c2ecf20Sopenharmony_ci		".machine power8\n"			\
9648c2ecf20Sopenharmony_ci		"1:	" op " %2,0,%3\n"		\
9658c2ecf20Sopenharmony_ci		".machine pop\n"			\
9668c2ecf20Sopenharmony_ci		"	mfcr	%1\n"			\
9678c2ecf20Sopenharmony_ci		"2:\n"					\
9688c2ecf20Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
9698c2ecf20Sopenharmony_ci		"3:	li	%0,%4\n"		\
9708c2ecf20Sopenharmony_ci		"	b	2b\n"			\
9718c2ecf20Sopenharmony_ci		".previous\n"				\
9728c2ecf20Sopenharmony_ci		EX_TABLE(1b, 3b)			\
9738c2ecf20Sopenharmony_ci		: "=r" (err), "=r" (cr)			\
9748c2ecf20Sopenharmony_ci		: "r" (x), "r" (addr), "i" (-EFAULT), "0" (err))
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci#define __get_user_asmx(x, addr, err, op)		\
9778c2ecf20Sopenharmony_ci	__asm__ __volatile__(				\
9788c2ecf20Sopenharmony_ci		".machine push\n"			\
9798c2ecf20Sopenharmony_ci		".machine power8\n"			\
9808c2ecf20Sopenharmony_ci		"1:	"op" %1,0,%2\n"			\
9818c2ecf20Sopenharmony_ci		".machine pop\n"			\
9828c2ecf20Sopenharmony_ci		"2:\n"					\
9838c2ecf20Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
9848c2ecf20Sopenharmony_ci		"3:	li	%0,%3\n"		\
9858c2ecf20Sopenharmony_ci		"	b	2b\n"			\
9868c2ecf20Sopenharmony_ci		".previous\n"				\
9878c2ecf20Sopenharmony_ci		EX_TABLE(1b, 3b)			\
9888c2ecf20Sopenharmony_ci		: "=r" (err), "=r" (x)			\
9898c2ecf20Sopenharmony_ci		: "r" (addr), "i" (-EFAULT), "0" (err))
9908c2ecf20Sopenharmony_ci
9918c2ecf20Sopenharmony_ci#define __cacheop_user_asmx(addr, err, op)		\
9928c2ecf20Sopenharmony_ci	__asm__ __volatile__(				\
9938c2ecf20Sopenharmony_ci		"1:	"op" 0,%1\n"			\
9948c2ecf20Sopenharmony_ci		"2:\n"					\
9958c2ecf20Sopenharmony_ci		".section .fixup,\"ax\"\n"		\
9968c2ecf20Sopenharmony_ci		"3:	li	%0,%3\n"		\
9978c2ecf20Sopenharmony_ci		"	b	2b\n"			\
9988c2ecf20Sopenharmony_ci		".previous\n"				\
9998c2ecf20Sopenharmony_ci		EX_TABLE(1b, 3b)			\
10008c2ecf20Sopenharmony_ci		: "=r" (err)				\
10018c2ecf20Sopenharmony_ci		: "r" (addr), "i" (-EFAULT), "0" (err))
10028c2ecf20Sopenharmony_ci
10038c2ecf20Sopenharmony_cistatic nokprobe_inline void set_cr0(const struct pt_regs *regs,
10048c2ecf20Sopenharmony_ci				    struct instruction_op *op)
10058c2ecf20Sopenharmony_ci{
10068c2ecf20Sopenharmony_ci	long val = op->val;
10078c2ecf20Sopenharmony_ci
10088c2ecf20Sopenharmony_ci	op->type |= SETCC;
10098c2ecf20Sopenharmony_ci	op->ccval = (regs->ccr & 0x0fffffff) | ((regs->xer >> 3) & 0x10000000);
10108c2ecf20Sopenharmony_ci#ifdef __powerpc64__
10118c2ecf20Sopenharmony_ci	if (!(regs->msr & MSR_64BIT))
10128c2ecf20Sopenharmony_ci		val = (int) val;
10138c2ecf20Sopenharmony_ci#endif
10148c2ecf20Sopenharmony_ci	if (val < 0)
10158c2ecf20Sopenharmony_ci		op->ccval |= 0x80000000;
10168c2ecf20Sopenharmony_ci	else if (val > 0)
10178c2ecf20Sopenharmony_ci		op->ccval |= 0x40000000;
10188c2ecf20Sopenharmony_ci	else
10198c2ecf20Sopenharmony_ci		op->ccval |= 0x20000000;
10208c2ecf20Sopenharmony_ci}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistatic nokprobe_inline void set_ca32(struct instruction_op *op, bool val)
10238c2ecf20Sopenharmony_ci{
10248c2ecf20Sopenharmony_ci	if (cpu_has_feature(CPU_FTR_ARCH_300)) {
10258c2ecf20Sopenharmony_ci		if (val)
10268c2ecf20Sopenharmony_ci			op->xerval |= XER_CA32;
10278c2ecf20Sopenharmony_ci		else
10288c2ecf20Sopenharmony_ci			op->xerval &= ~XER_CA32;
10298c2ecf20Sopenharmony_ci	}
10308c2ecf20Sopenharmony_ci}
10318c2ecf20Sopenharmony_ci
10328c2ecf20Sopenharmony_cistatic nokprobe_inline void add_with_carry(const struct pt_regs *regs,
10338c2ecf20Sopenharmony_ci				     struct instruction_op *op, int rd,
10348c2ecf20Sopenharmony_ci				     unsigned long val1, unsigned long val2,
10358c2ecf20Sopenharmony_ci				     unsigned long carry_in)
10368c2ecf20Sopenharmony_ci{
10378c2ecf20Sopenharmony_ci	unsigned long val = val1 + val2;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	if (carry_in)
10408c2ecf20Sopenharmony_ci		++val;
10418c2ecf20Sopenharmony_ci	op->type = COMPUTE + SETREG + SETXER;
10428c2ecf20Sopenharmony_ci	op->reg = rd;
10438c2ecf20Sopenharmony_ci	op->val = val;
10448c2ecf20Sopenharmony_ci#ifdef __powerpc64__
10458c2ecf20Sopenharmony_ci	if (!(regs->msr & MSR_64BIT)) {
10468c2ecf20Sopenharmony_ci		val = (unsigned int) val;
10478c2ecf20Sopenharmony_ci		val1 = (unsigned int) val1;
10488c2ecf20Sopenharmony_ci	}
10498c2ecf20Sopenharmony_ci#endif
10508c2ecf20Sopenharmony_ci	op->xerval = regs->xer;
10518c2ecf20Sopenharmony_ci	if (val < val1 || (carry_in && val == val1))
10528c2ecf20Sopenharmony_ci		op->xerval |= XER_CA;
10538c2ecf20Sopenharmony_ci	else
10548c2ecf20Sopenharmony_ci		op->xerval &= ~XER_CA;
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	set_ca32(op, (unsigned int)val < (unsigned int)val1 ||
10578c2ecf20Sopenharmony_ci			(carry_in && (unsigned int)val == (unsigned int)val1));
10588c2ecf20Sopenharmony_ci}
10598c2ecf20Sopenharmony_ci
10608c2ecf20Sopenharmony_cistatic nokprobe_inline void do_cmp_signed(const struct pt_regs *regs,
10618c2ecf20Sopenharmony_ci					  struct instruction_op *op,
10628c2ecf20Sopenharmony_ci					  long v1, long v2, int crfld)
10638c2ecf20Sopenharmony_ci{
10648c2ecf20Sopenharmony_ci	unsigned int crval, shift;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	op->type = COMPUTE + SETCC;
10678c2ecf20Sopenharmony_ci	crval = (regs->xer >> 31) & 1;		/* get SO bit */
10688c2ecf20Sopenharmony_ci	if (v1 < v2)
10698c2ecf20Sopenharmony_ci		crval |= 8;
10708c2ecf20Sopenharmony_ci	else if (v1 > v2)
10718c2ecf20Sopenharmony_ci		crval |= 4;
10728c2ecf20Sopenharmony_ci	else
10738c2ecf20Sopenharmony_ci		crval |= 2;
10748c2ecf20Sopenharmony_ci	shift = (7 - crfld) * 4;
10758c2ecf20Sopenharmony_ci	op->ccval = (regs->ccr & ~(0xf << shift)) | (crval << shift);
10768c2ecf20Sopenharmony_ci}
10778c2ecf20Sopenharmony_ci
10788c2ecf20Sopenharmony_cistatic nokprobe_inline void do_cmp_unsigned(const struct pt_regs *regs,
10798c2ecf20Sopenharmony_ci					    struct instruction_op *op,
10808c2ecf20Sopenharmony_ci					    unsigned long v1,
10818c2ecf20Sopenharmony_ci					    unsigned long v2, int crfld)
10828c2ecf20Sopenharmony_ci{
10838c2ecf20Sopenharmony_ci	unsigned int crval, shift;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	op->type = COMPUTE + SETCC;
10868c2ecf20Sopenharmony_ci	crval = (regs->xer >> 31) & 1;		/* get SO bit */
10878c2ecf20Sopenharmony_ci	if (v1 < v2)
10888c2ecf20Sopenharmony_ci		crval |= 8;
10898c2ecf20Sopenharmony_ci	else if (v1 > v2)
10908c2ecf20Sopenharmony_ci		crval |= 4;
10918c2ecf20Sopenharmony_ci	else
10928c2ecf20Sopenharmony_ci		crval |= 2;
10938c2ecf20Sopenharmony_ci	shift = (7 - crfld) * 4;
10948c2ecf20Sopenharmony_ci	op->ccval = (regs->ccr & ~(0xf << shift)) | (crval << shift);
10958c2ecf20Sopenharmony_ci}
10968c2ecf20Sopenharmony_ci
10978c2ecf20Sopenharmony_cistatic nokprobe_inline void do_cmpb(const struct pt_regs *regs,
10988c2ecf20Sopenharmony_ci				    struct instruction_op *op,
10998c2ecf20Sopenharmony_ci				    unsigned long v1, unsigned long v2)
11008c2ecf20Sopenharmony_ci{
11018c2ecf20Sopenharmony_ci	unsigned long long out_val, mask;
11028c2ecf20Sopenharmony_ci	int i;
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	out_val = 0;
11058c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
11068c2ecf20Sopenharmony_ci		mask = 0xffUL << (i * 8);
11078c2ecf20Sopenharmony_ci		if ((v1 & mask) == (v2 & mask))
11088c2ecf20Sopenharmony_ci			out_val |= mask;
11098c2ecf20Sopenharmony_ci	}
11108c2ecf20Sopenharmony_ci	op->val = out_val;
11118c2ecf20Sopenharmony_ci}
11128c2ecf20Sopenharmony_ci
11138c2ecf20Sopenharmony_ci/*
11148c2ecf20Sopenharmony_ci * The size parameter is used to adjust the equivalent popcnt instruction.
11158c2ecf20Sopenharmony_ci * popcntb = 8, popcntw = 32, popcntd = 64
11168c2ecf20Sopenharmony_ci */
11178c2ecf20Sopenharmony_cistatic nokprobe_inline void do_popcnt(const struct pt_regs *regs,
11188c2ecf20Sopenharmony_ci				      struct instruction_op *op,
11198c2ecf20Sopenharmony_ci				      unsigned long v1, int size)
11208c2ecf20Sopenharmony_ci{
11218c2ecf20Sopenharmony_ci	unsigned long long out = v1;
11228c2ecf20Sopenharmony_ci
11238c2ecf20Sopenharmony_ci	out -= (out >> 1) & 0x5555555555555555ULL;
11248c2ecf20Sopenharmony_ci	out = (0x3333333333333333ULL & out) +
11258c2ecf20Sopenharmony_ci	      (0x3333333333333333ULL & (out >> 2));
11268c2ecf20Sopenharmony_ci	out = (out + (out >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
11278c2ecf20Sopenharmony_ci
11288c2ecf20Sopenharmony_ci	if (size == 8) {	/* popcntb */
11298c2ecf20Sopenharmony_ci		op->val = out;
11308c2ecf20Sopenharmony_ci		return;
11318c2ecf20Sopenharmony_ci	}
11328c2ecf20Sopenharmony_ci	out += out >> 8;
11338c2ecf20Sopenharmony_ci	out += out >> 16;
11348c2ecf20Sopenharmony_ci	if (size == 32) {	/* popcntw */
11358c2ecf20Sopenharmony_ci		op->val = out & 0x0000003f0000003fULL;
11368c2ecf20Sopenharmony_ci		return;
11378c2ecf20Sopenharmony_ci	}
11388c2ecf20Sopenharmony_ci
11398c2ecf20Sopenharmony_ci	out = (out + (out >> 32)) & 0x7f;
11408c2ecf20Sopenharmony_ci	op->val = out;	/* popcntd */
11418c2ecf20Sopenharmony_ci}
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
11448c2ecf20Sopenharmony_cistatic nokprobe_inline void do_bpermd(const struct pt_regs *regs,
11458c2ecf20Sopenharmony_ci				      struct instruction_op *op,
11468c2ecf20Sopenharmony_ci				      unsigned long v1, unsigned long v2)
11478c2ecf20Sopenharmony_ci{
11488c2ecf20Sopenharmony_ci	unsigned char perm, idx;
11498c2ecf20Sopenharmony_ci	unsigned int i;
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci	perm = 0;
11528c2ecf20Sopenharmony_ci	for (i = 0; i < 8; i++) {
11538c2ecf20Sopenharmony_ci		idx = (v1 >> (i * 8)) & 0xff;
11548c2ecf20Sopenharmony_ci		if (idx < 64)
11558c2ecf20Sopenharmony_ci			if (v2 & PPC_BIT(idx))
11568c2ecf20Sopenharmony_ci				perm |= 1 << i;
11578c2ecf20Sopenharmony_ci	}
11588c2ecf20Sopenharmony_ci	op->val = perm;
11598c2ecf20Sopenharmony_ci}
11608c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC64 */
11618c2ecf20Sopenharmony_ci/*
11628c2ecf20Sopenharmony_ci * The size parameter adjusts the equivalent prty instruction.
11638c2ecf20Sopenharmony_ci * prtyw = 32, prtyd = 64
11648c2ecf20Sopenharmony_ci */
11658c2ecf20Sopenharmony_cistatic nokprobe_inline void do_prty(const struct pt_regs *regs,
11668c2ecf20Sopenharmony_ci				    struct instruction_op *op,
11678c2ecf20Sopenharmony_ci				    unsigned long v, int size)
11688c2ecf20Sopenharmony_ci{
11698c2ecf20Sopenharmony_ci	unsigned long long res = v ^ (v >> 8);
11708c2ecf20Sopenharmony_ci
11718c2ecf20Sopenharmony_ci	res ^= res >> 16;
11728c2ecf20Sopenharmony_ci	if (size == 32) {		/* prtyw */
11738c2ecf20Sopenharmony_ci		op->val = res & 0x0000000100000001ULL;
11748c2ecf20Sopenharmony_ci		return;
11758c2ecf20Sopenharmony_ci	}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	res ^= res >> 32;
11788c2ecf20Sopenharmony_ci	op->val = res & 1;	/*prtyd */
11798c2ecf20Sopenharmony_ci}
11808c2ecf20Sopenharmony_ci
11818c2ecf20Sopenharmony_cistatic nokprobe_inline int trap_compare(long v1, long v2)
11828c2ecf20Sopenharmony_ci{
11838c2ecf20Sopenharmony_ci	int ret = 0;
11848c2ecf20Sopenharmony_ci
11858c2ecf20Sopenharmony_ci	if (v1 < v2)
11868c2ecf20Sopenharmony_ci		ret |= 0x10;
11878c2ecf20Sopenharmony_ci	else if (v1 > v2)
11888c2ecf20Sopenharmony_ci		ret |= 0x08;
11898c2ecf20Sopenharmony_ci	else
11908c2ecf20Sopenharmony_ci		ret |= 0x04;
11918c2ecf20Sopenharmony_ci	if ((unsigned long)v1 < (unsigned long)v2)
11928c2ecf20Sopenharmony_ci		ret |= 0x02;
11938c2ecf20Sopenharmony_ci	else if ((unsigned long)v1 > (unsigned long)v2)
11948c2ecf20Sopenharmony_ci		ret |= 0x01;
11958c2ecf20Sopenharmony_ci	return ret;
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci/*
11998c2ecf20Sopenharmony_ci * Elements of 32-bit rotate and mask instructions.
12008c2ecf20Sopenharmony_ci */
12018c2ecf20Sopenharmony_ci#define MASK32(mb, me)	((0xffffffffUL >> (mb)) + \
12028c2ecf20Sopenharmony_ci			 ((signed long)-0x80000000L >> (me)) + ((me) >= (mb)))
12038c2ecf20Sopenharmony_ci#ifdef __powerpc64__
12048c2ecf20Sopenharmony_ci#define MASK64_L(mb)	(~0UL >> (mb))
12058c2ecf20Sopenharmony_ci#define MASK64_R(me)	((signed long)-0x8000000000000000L >> (me))
12068c2ecf20Sopenharmony_ci#define MASK64(mb, me)	(MASK64_L(mb) + MASK64_R(me) + ((me) >= (mb)))
12078c2ecf20Sopenharmony_ci#define DATA32(x)	(((x) & 0xffffffffUL) | (((x) & 0xffffffffUL) << 32))
12088c2ecf20Sopenharmony_ci#else
12098c2ecf20Sopenharmony_ci#define DATA32(x)	(x)
12108c2ecf20Sopenharmony_ci#endif
12118c2ecf20Sopenharmony_ci#define ROTATE(x, n)	((n) ? (((x) << (n)) | ((x) >> (8 * sizeof(long) - (n)))) : (x))
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci/*
12148c2ecf20Sopenharmony_ci * Decode an instruction, and return information about it in *op
12158c2ecf20Sopenharmony_ci * without changing *regs.
12168c2ecf20Sopenharmony_ci * Integer arithmetic and logical instructions, branches, and barrier
12178c2ecf20Sopenharmony_ci * instructions can be emulated just using the information in *op.
12188c2ecf20Sopenharmony_ci *
12198c2ecf20Sopenharmony_ci * Return value is 1 if the instruction can be emulated just by
12208c2ecf20Sopenharmony_ci * updating *regs with the information in *op, -1 if we need the
12218c2ecf20Sopenharmony_ci * GPRs but *regs doesn't contain the full register set, or 0
12228c2ecf20Sopenharmony_ci * otherwise.
12238c2ecf20Sopenharmony_ci */
12248c2ecf20Sopenharmony_ciint analyse_instr(struct instruction_op *op, const struct pt_regs *regs,
12258c2ecf20Sopenharmony_ci		  struct ppc_inst instr)
12268c2ecf20Sopenharmony_ci{
12278c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
12288c2ecf20Sopenharmony_ci	unsigned int suffixopcode, prefixtype, prefix_r;
12298c2ecf20Sopenharmony_ci#endif
12308c2ecf20Sopenharmony_ci	unsigned int opcode, ra, rb, rc, rd, spr, u;
12318c2ecf20Sopenharmony_ci	unsigned long int imm;
12328c2ecf20Sopenharmony_ci	unsigned long int val, val2;
12338c2ecf20Sopenharmony_ci	unsigned int mb, me, sh;
12348c2ecf20Sopenharmony_ci	unsigned int word, suffix;
12358c2ecf20Sopenharmony_ci	long ival;
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	word = ppc_inst_val(instr);
12388c2ecf20Sopenharmony_ci	suffix = ppc_inst_suffix(instr);
12398c2ecf20Sopenharmony_ci
12408c2ecf20Sopenharmony_ci	op->type = COMPUTE;
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci	opcode = ppc_inst_primary_opcode(instr);
12438c2ecf20Sopenharmony_ci	switch (opcode) {
12448c2ecf20Sopenharmony_ci	case 16:	/* bc */
12458c2ecf20Sopenharmony_ci		op->type = BRANCH;
12468c2ecf20Sopenharmony_ci		imm = (signed short)(word & 0xfffc);
12478c2ecf20Sopenharmony_ci		if ((word & 2) == 0)
12488c2ecf20Sopenharmony_ci			imm += regs->nip;
12498c2ecf20Sopenharmony_ci		op->val = truncate_if_32bit(regs->msr, imm);
12508c2ecf20Sopenharmony_ci		if (word & 1)
12518c2ecf20Sopenharmony_ci			op->type |= SETLK;
12528c2ecf20Sopenharmony_ci		if (branch_taken(word, regs, op))
12538c2ecf20Sopenharmony_ci			op->type |= BRTAKEN;
12548c2ecf20Sopenharmony_ci		return 1;
12558c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
12568c2ecf20Sopenharmony_ci	case 17:	/* sc */
12578c2ecf20Sopenharmony_ci		if ((word & 0xfe2) == 2)
12588c2ecf20Sopenharmony_ci			op->type = SYSCALL;
12598c2ecf20Sopenharmony_ci		else if (IS_ENABLED(CONFIG_PPC_BOOK3S_64) &&
12608c2ecf20Sopenharmony_ci				(word & 0xfe3) == 1) {	/* scv */
12618c2ecf20Sopenharmony_ci			op->type = SYSCALL_VECTORED_0;
12628c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
12638c2ecf20Sopenharmony_ci				goto unknown_opcode;
12648c2ecf20Sopenharmony_ci		} else
12658c2ecf20Sopenharmony_ci			op->type = UNKNOWN;
12668c2ecf20Sopenharmony_ci		return 0;
12678c2ecf20Sopenharmony_ci#endif
12688c2ecf20Sopenharmony_ci	case 18:	/* b */
12698c2ecf20Sopenharmony_ci		op->type = BRANCH | BRTAKEN;
12708c2ecf20Sopenharmony_ci		imm = word & 0x03fffffc;
12718c2ecf20Sopenharmony_ci		if (imm & 0x02000000)
12728c2ecf20Sopenharmony_ci			imm -= 0x04000000;
12738c2ecf20Sopenharmony_ci		if ((word & 2) == 0)
12748c2ecf20Sopenharmony_ci			imm += regs->nip;
12758c2ecf20Sopenharmony_ci		op->val = truncate_if_32bit(regs->msr, imm);
12768c2ecf20Sopenharmony_ci		if (word & 1)
12778c2ecf20Sopenharmony_ci			op->type |= SETLK;
12788c2ecf20Sopenharmony_ci		return 1;
12798c2ecf20Sopenharmony_ci	case 19:
12808c2ecf20Sopenharmony_ci		switch ((word >> 1) & 0x3ff) {
12818c2ecf20Sopenharmony_ci		case 0:		/* mcrf */
12828c2ecf20Sopenharmony_ci			op->type = COMPUTE + SETCC;
12838c2ecf20Sopenharmony_ci			rd = 7 - ((word >> 23) & 0x7);
12848c2ecf20Sopenharmony_ci			ra = 7 - ((word >> 18) & 0x7);
12858c2ecf20Sopenharmony_ci			rd *= 4;
12868c2ecf20Sopenharmony_ci			ra *= 4;
12878c2ecf20Sopenharmony_ci			val = (regs->ccr >> ra) & 0xf;
12888c2ecf20Sopenharmony_ci			op->ccval = (regs->ccr & ~(0xfUL << rd)) | (val << rd);
12898c2ecf20Sopenharmony_ci			return 1;
12908c2ecf20Sopenharmony_ci
12918c2ecf20Sopenharmony_ci		case 16:	/* bclr */
12928c2ecf20Sopenharmony_ci		case 528:	/* bcctr */
12938c2ecf20Sopenharmony_ci			op->type = BRANCH;
12948c2ecf20Sopenharmony_ci			imm = (word & 0x400)? regs->ctr: regs->link;
12958c2ecf20Sopenharmony_ci			op->val = truncate_if_32bit(regs->msr, imm);
12968c2ecf20Sopenharmony_ci			if (word & 1)
12978c2ecf20Sopenharmony_ci				op->type |= SETLK;
12988c2ecf20Sopenharmony_ci			if (branch_taken(word, regs, op))
12998c2ecf20Sopenharmony_ci				op->type |= BRTAKEN;
13008c2ecf20Sopenharmony_ci			return 1;
13018c2ecf20Sopenharmony_ci
13028c2ecf20Sopenharmony_ci		case 18:	/* rfid, scary */
13038c2ecf20Sopenharmony_ci			if (regs->msr & MSR_PR)
13048c2ecf20Sopenharmony_ci				goto priv;
13058c2ecf20Sopenharmony_ci			op->type = RFI;
13068c2ecf20Sopenharmony_ci			return 0;
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci		case 150:	/* isync */
13098c2ecf20Sopenharmony_ci			op->type = BARRIER | BARRIER_ISYNC;
13108c2ecf20Sopenharmony_ci			return 1;
13118c2ecf20Sopenharmony_ci
13128c2ecf20Sopenharmony_ci		case 33:	/* crnor */
13138c2ecf20Sopenharmony_ci		case 129:	/* crandc */
13148c2ecf20Sopenharmony_ci		case 193:	/* crxor */
13158c2ecf20Sopenharmony_ci		case 225:	/* crnand */
13168c2ecf20Sopenharmony_ci		case 257:	/* crand */
13178c2ecf20Sopenharmony_ci		case 289:	/* creqv */
13188c2ecf20Sopenharmony_ci		case 417:	/* crorc */
13198c2ecf20Sopenharmony_ci		case 449:	/* cror */
13208c2ecf20Sopenharmony_ci			op->type = COMPUTE + SETCC;
13218c2ecf20Sopenharmony_ci			ra = (word >> 16) & 0x1f;
13228c2ecf20Sopenharmony_ci			rb = (word >> 11) & 0x1f;
13238c2ecf20Sopenharmony_ci			rd = (word >> 21) & 0x1f;
13248c2ecf20Sopenharmony_ci			ra = (regs->ccr >> (31 - ra)) & 1;
13258c2ecf20Sopenharmony_ci			rb = (regs->ccr >> (31 - rb)) & 1;
13268c2ecf20Sopenharmony_ci			val = (word >> (6 + ra * 2 + rb)) & 1;
13278c2ecf20Sopenharmony_ci			op->ccval = (regs->ccr & ~(1UL << (31 - rd))) |
13288c2ecf20Sopenharmony_ci				(val << (31 - rd));
13298c2ecf20Sopenharmony_ci			return 1;
13308c2ecf20Sopenharmony_ci		}
13318c2ecf20Sopenharmony_ci		break;
13328c2ecf20Sopenharmony_ci	case 31:
13338c2ecf20Sopenharmony_ci		switch ((word >> 1) & 0x3ff) {
13348c2ecf20Sopenharmony_ci		case 598:	/* sync */
13358c2ecf20Sopenharmony_ci			op->type = BARRIER + BARRIER_SYNC;
13368c2ecf20Sopenharmony_ci#ifdef __powerpc64__
13378c2ecf20Sopenharmony_ci			switch ((word >> 21) & 3) {
13388c2ecf20Sopenharmony_ci			case 1:		/* lwsync */
13398c2ecf20Sopenharmony_ci				op->type = BARRIER + BARRIER_LWSYNC;
13408c2ecf20Sopenharmony_ci				break;
13418c2ecf20Sopenharmony_ci			case 2:		/* ptesync */
13428c2ecf20Sopenharmony_ci				op->type = BARRIER + BARRIER_PTESYNC;
13438c2ecf20Sopenharmony_ci				break;
13448c2ecf20Sopenharmony_ci			}
13458c2ecf20Sopenharmony_ci#endif
13468c2ecf20Sopenharmony_ci			return 1;
13478c2ecf20Sopenharmony_ci
13488c2ecf20Sopenharmony_ci		case 854:	/* eieio */
13498c2ecf20Sopenharmony_ci			op->type = BARRIER + BARRIER_EIEIO;
13508c2ecf20Sopenharmony_ci			return 1;
13518c2ecf20Sopenharmony_ci		}
13528c2ecf20Sopenharmony_ci		break;
13538c2ecf20Sopenharmony_ci	}
13548c2ecf20Sopenharmony_ci
13558c2ecf20Sopenharmony_ci	/* Following cases refer to regs->gpr[], so we need all regs */
13568c2ecf20Sopenharmony_ci	if (!FULL_REGS(regs))
13578c2ecf20Sopenharmony_ci		return -1;
13588c2ecf20Sopenharmony_ci
13598c2ecf20Sopenharmony_ci	rd = (word >> 21) & 0x1f;
13608c2ecf20Sopenharmony_ci	ra = (word >> 16) & 0x1f;
13618c2ecf20Sopenharmony_ci	rb = (word >> 11) & 0x1f;
13628c2ecf20Sopenharmony_ci	rc = (word >> 6) & 0x1f;
13638c2ecf20Sopenharmony_ci
13648c2ecf20Sopenharmony_ci	switch (opcode) {
13658c2ecf20Sopenharmony_ci#ifdef __powerpc64__
13668c2ecf20Sopenharmony_ci	case 1:
13678c2ecf20Sopenharmony_ci		if (!cpu_has_feature(CPU_FTR_ARCH_31))
13688c2ecf20Sopenharmony_ci			goto unknown_opcode;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci		prefix_r = GET_PREFIX_R(word);
13718c2ecf20Sopenharmony_ci		ra = GET_PREFIX_RA(suffix);
13728c2ecf20Sopenharmony_ci		rd = (suffix >> 21) & 0x1f;
13738c2ecf20Sopenharmony_ci		op->reg = rd;
13748c2ecf20Sopenharmony_ci		op->val = regs->gpr[rd];
13758c2ecf20Sopenharmony_ci		suffixopcode = get_op(suffix);
13768c2ecf20Sopenharmony_ci		prefixtype = (word >> 24) & 0x3;
13778c2ecf20Sopenharmony_ci		switch (prefixtype) {
13788c2ecf20Sopenharmony_ci		case 2:
13798c2ecf20Sopenharmony_ci			if (prefix_r && ra)
13808c2ecf20Sopenharmony_ci				return 0;
13818c2ecf20Sopenharmony_ci			switch (suffixopcode) {
13828c2ecf20Sopenharmony_ci			case 14:	/* paddi */
13838c2ecf20Sopenharmony_ci				op->type = COMPUTE | PREFIXED;
13848c2ecf20Sopenharmony_ci				op->val = mlsd_8lsd_ea(word, suffix, regs);
13858c2ecf20Sopenharmony_ci				goto compute_done;
13868c2ecf20Sopenharmony_ci			}
13878c2ecf20Sopenharmony_ci		}
13888c2ecf20Sopenharmony_ci		break;
13898c2ecf20Sopenharmony_ci	case 2:		/* tdi */
13908c2ecf20Sopenharmony_ci		if (rd & trap_compare(regs->gpr[ra], (short) word))
13918c2ecf20Sopenharmony_ci			goto trap;
13928c2ecf20Sopenharmony_ci		return 1;
13938c2ecf20Sopenharmony_ci#endif
13948c2ecf20Sopenharmony_ci	case 3:		/* twi */
13958c2ecf20Sopenharmony_ci		if (rd & trap_compare((int)regs->gpr[ra], (short) word))
13968c2ecf20Sopenharmony_ci			goto trap;
13978c2ecf20Sopenharmony_ci		return 1;
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci#ifdef __powerpc64__
14008c2ecf20Sopenharmony_ci	case 4:
14018c2ecf20Sopenharmony_ci		/*
14028c2ecf20Sopenharmony_ci		 * There are very many instructions with this primary opcode
14038c2ecf20Sopenharmony_ci		 * introduced in the ISA as early as v2.03. However, the ones
14048c2ecf20Sopenharmony_ci		 * we currently emulate were all introduced with ISA 3.0
14058c2ecf20Sopenharmony_ci		 */
14068c2ecf20Sopenharmony_ci		if (!cpu_has_feature(CPU_FTR_ARCH_300))
14078c2ecf20Sopenharmony_ci			goto unknown_opcode;
14088c2ecf20Sopenharmony_ci
14098c2ecf20Sopenharmony_ci		switch (word & 0x3f) {
14108c2ecf20Sopenharmony_ci		case 48:	/* maddhd */
14118c2ecf20Sopenharmony_ci			asm volatile(PPC_MADDHD(%0, %1, %2, %3) :
14128c2ecf20Sopenharmony_ci				     "=r" (op->val) : "r" (regs->gpr[ra]),
14138c2ecf20Sopenharmony_ci				     "r" (regs->gpr[rb]), "r" (regs->gpr[rc]));
14148c2ecf20Sopenharmony_ci			goto compute_done;
14158c2ecf20Sopenharmony_ci
14168c2ecf20Sopenharmony_ci		case 49:	/* maddhdu */
14178c2ecf20Sopenharmony_ci			asm volatile(PPC_MADDHDU(%0, %1, %2, %3) :
14188c2ecf20Sopenharmony_ci				     "=r" (op->val) : "r" (regs->gpr[ra]),
14198c2ecf20Sopenharmony_ci				     "r" (regs->gpr[rb]), "r" (regs->gpr[rc]));
14208c2ecf20Sopenharmony_ci			goto compute_done;
14218c2ecf20Sopenharmony_ci
14228c2ecf20Sopenharmony_ci		case 51:	/* maddld */
14238c2ecf20Sopenharmony_ci			asm volatile(PPC_MADDLD(%0, %1, %2, %3) :
14248c2ecf20Sopenharmony_ci				     "=r" (op->val) : "r" (regs->gpr[ra]),
14258c2ecf20Sopenharmony_ci				     "r" (regs->gpr[rb]), "r" (regs->gpr[rc]));
14268c2ecf20Sopenharmony_ci			goto compute_done;
14278c2ecf20Sopenharmony_ci		}
14288c2ecf20Sopenharmony_ci
14298c2ecf20Sopenharmony_ci		/*
14308c2ecf20Sopenharmony_ci		 * There are other instructions from ISA 3.0 with the same
14318c2ecf20Sopenharmony_ci		 * primary opcode which do not have emulation support yet.
14328c2ecf20Sopenharmony_ci		 */
14338c2ecf20Sopenharmony_ci		goto unknown_opcode;
14348c2ecf20Sopenharmony_ci#endif
14358c2ecf20Sopenharmony_ci
14368c2ecf20Sopenharmony_ci	case 7:		/* mulli */
14378c2ecf20Sopenharmony_ci		op->val = regs->gpr[ra] * (short) word;
14388c2ecf20Sopenharmony_ci		goto compute_done;
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	case 8:		/* subfic */
14418c2ecf20Sopenharmony_ci		imm = (short) word;
14428c2ecf20Sopenharmony_ci		add_with_carry(regs, op, rd, ~regs->gpr[ra], imm, 1);
14438c2ecf20Sopenharmony_ci		return 1;
14448c2ecf20Sopenharmony_ci
14458c2ecf20Sopenharmony_ci	case 10:	/* cmpli */
14468c2ecf20Sopenharmony_ci		imm = (unsigned short) word;
14478c2ecf20Sopenharmony_ci		val = regs->gpr[ra];
14488c2ecf20Sopenharmony_ci#ifdef __powerpc64__
14498c2ecf20Sopenharmony_ci		if ((rd & 1) == 0)
14508c2ecf20Sopenharmony_ci			val = (unsigned int) val;
14518c2ecf20Sopenharmony_ci#endif
14528c2ecf20Sopenharmony_ci		do_cmp_unsigned(regs, op, val, imm, rd >> 2);
14538c2ecf20Sopenharmony_ci		return 1;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	case 11:	/* cmpi */
14568c2ecf20Sopenharmony_ci		imm = (short) word;
14578c2ecf20Sopenharmony_ci		val = regs->gpr[ra];
14588c2ecf20Sopenharmony_ci#ifdef __powerpc64__
14598c2ecf20Sopenharmony_ci		if ((rd & 1) == 0)
14608c2ecf20Sopenharmony_ci			val = (int) val;
14618c2ecf20Sopenharmony_ci#endif
14628c2ecf20Sopenharmony_ci		do_cmp_signed(regs, op, val, imm, rd >> 2);
14638c2ecf20Sopenharmony_ci		return 1;
14648c2ecf20Sopenharmony_ci
14658c2ecf20Sopenharmony_ci	case 12:	/* addic */
14668c2ecf20Sopenharmony_ci		imm = (short) word;
14678c2ecf20Sopenharmony_ci		add_with_carry(regs, op, rd, regs->gpr[ra], imm, 0);
14688c2ecf20Sopenharmony_ci		return 1;
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	case 13:	/* addic. */
14718c2ecf20Sopenharmony_ci		imm = (short) word;
14728c2ecf20Sopenharmony_ci		add_with_carry(regs, op, rd, regs->gpr[ra], imm, 0);
14738c2ecf20Sopenharmony_ci		set_cr0(regs, op);
14748c2ecf20Sopenharmony_ci		return 1;
14758c2ecf20Sopenharmony_ci
14768c2ecf20Sopenharmony_ci	case 14:	/* addi */
14778c2ecf20Sopenharmony_ci		imm = (short) word;
14788c2ecf20Sopenharmony_ci		if (ra)
14798c2ecf20Sopenharmony_ci			imm += regs->gpr[ra];
14808c2ecf20Sopenharmony_ci		op->val = imm;
14818c2ecf20Sopenharmony_ci		goto compute_done;
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	case 15:	/* addis */
14848c2ecf20Sopenharmony_ci		imm = ((short) word) << 16;
14858c2ecf20Sopenharmony_ci		if (ra)
14868c2ecf20Sopenharmony_ci			imm += regs->gpr[ra];
14878c2ecf20Sopenharmony_ci		op->val = imm;
14888c2ecf20Sopenharmony_ci		goto compute_done;
14898c2ecf20Sopenharmony_ci
14908c2ecf20Sopenharmony_ci	case 19:
14918c2ecf20Sopenharmony_ci		if (((word >> 1) & 0x1f) == 2) {
14928c2ecf20Sopenharmony_ci			/* addpcis */
14938c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
14948c2ecf20Sopenharmony_ci				goto unknown_opcode;
14958c2ecf20Sopenharmony_ci			imm = (short) (word & 0xffc1);	/* d0 + d2 fields */
14968c2ecf20Sopenharmony_ci			imm |= (word >> 15) & 0x3e;	/* d1 field */
14978c2ecf20Sopenharmony_ci			op->val = regs->nip + (imm << 16) + 4;
14988c2ecf20Sopenharmony_ci			goto compute_done;
14998c2ecf20Sopenharmony_ci		}
15008c2ecf20Sopenharmony_ci		op->type = UNKNOWN;
15018c2ecf20Sopenharmony_ci		return 0;
15028c2ecf20Sopenharmony_ci
15038c2ecf20Sopenharmony_ci	case 20:	/* rlwimi */
15048c2ecf20Sopenharmony_ci		mb = (word >> 6) & 0x1f;
15058c2ecf20Sopenharmony_ci		me = (word >> 1) & 0x1f;
15068c2ecf20Sopenharmony_ci		val = DATA32(regs->gpr[rd]);
15078c2ecf20Sopenharmony_ci		imm = MASK32(mb, me);
15088c2ecf20Sopenharmony_ci		op->val = (regs->gpr[ra] & ~imm) | (ROTATE(val, rb) & imm);
15098c2ecf20Sopenharmony_ci		goto logical_done;
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	case 21:	/* rlwinm */
15128c2ecf20Sopenharmony_ci		mb = (word >> 6) & 0x1f;
15138c2ecf20Sopenharmony_ci		me = (word >> 1) & 0x1f;
15148c2ecf20Sopenharmony_ci		val = DATA32(regs->gpr[rd]);
15158c2ecf20Sopenharmony_ci		op->val = ROTATE(val, rb) & MASK32(mb, me);
15168c2ecf20Sopenharmony_ci		goto logical_done;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci	case 23:	/* rlwnm */
15198c2ecf20Sopenharmony_ci		mb = (word >> 6) & 0x1f;
15208c2ecf20Sopenharmony_ci		me = (word >> 1) & 0x1f;
15218c2ecf20Sopenharmony_ci		rb = regs->gpr[rb] & 0x1f;
15228c2ecf20Sopenharmony_ci		val = DATA32(regs->gpr[rd]);
15238c2ecf20Sopenharmony_ci		op->val = ROTATE(val, rb) & MASK32(mb, me);
15248c2ecf20Sopenharmony_ci		goto logical_done;
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_ci	case 24:	/* ori */
15278c2ecf20Sopenharmony_ci		op->val = regs->gpr[rd] | (unsigned short) word;
15288c2ecf20Sopenharmony_ci		goto logical_done_nocc;
15298c2ecf20Sopenharmony_ci
15308c2ecf20Sopenharmony_ci	case 25:	/* oris */
15318c2ecf20Sopenharmony_ci		imm = (unsigned short) word;
15328c2ecf20Sopenharmony_ci		op->val = regs->gpr[rd] | (imm << 16);
15338c2ecf20Sopenharmony_ci		goto logical_done_nocc;
15348c2ecf20Sopenharmony_ci
15358c2ecf20Sopenharmony_ci	case 26:	/* xori */
15368c2ecf20Sopenharmony_ci		op->val = regs->gpr[rd] ^ (unsigned short) word;
15378c2ecf20Sopenharmony_ci		goto logical_done_nocc;
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	case 27:	/* xoris */
15408c2ecf20Sopenharmony_ci		imm = (unsigned short) word;
15418c2ecf20Sopenharmony_ci		op->val = regs->gpr[rd] ^ (imm << 16);
15428c2ecf20Sopenharmony_ci		goto logical_done_nocc;
15438c2ecf20Sopenharmony_ci
15448c2ecf20Sopenharmony_ci	case 28:	/* andi. */
15458c2ecf20Sopenharmony_ci		op->val = regs->gpr[rd] & (unsigned short) word;
15468c2ecf20Sopenharmony_ci		set_cr0(regs, op);
15478c2ecf20Sopenharmony_ci		goto logical_done_nocc;
15488c2ecf20Sopenharmony_ci
15498c2ecf20Sopenharmony_ci	case 29:	/* andis. */
15508c2ecf20Sopenharmony_ci		imm = (unsigned short) word;
15518c2ecf20Sopenharmony_ci		op->val = regs->gpr[rd] & (imm << 16);
15528c2ecf20Sopenharmony_ci		set_cr0(regs, op);
15538c2ecf20Sopenharmony_ci		goto logical_done_nocc;
15548c2ecf20Sopenharmony_ci
15558c2ecf20Sopenharmony_ci#ifdef __powerpc64__
15568c2ecf20Sopenharmony_ci	case 30:	/* rld* */
15578c2ecf20Sopenharmony_ci		mb = ((word >> 6) & 0x1f) | (word & 0x20);
15588c2ecf20Sopenharmony_ci		val = regs->gpr[rd];
15598c2ecf20Sopenharmony_ci		if ((word & 0x10) == 0) {
15608c2ecf20Sopenharmony_ci			sh = rb | ((word & 2) << 4);
15618c2ecf20Sopenharmony_ci			val = ROTATE(val, sh);
15628c2ecf20Sopenharmony_ci			switch ((word >> 2) & 3) {
15638c2ecf20Sopenharmony_ci			case 0:		/* rldicl */
15648c2ecf20Sopenharmony_ci				val &= MASK64_L(mb);
15658c2ecf20Sopenharmony_ci				break;
15668c2ecf20Sopenharmony_ci			case 1:		/* rldicr */
15678c2ecf20Sopenharmony_ci				val &= MASK64_R(mb);
15688c2ecf20Sopenharmony_ci				break;
15698c2ecf20Sopenharmony_ci			case 2:		/* rldic */
15708c2ecf20Sopenharmony_ci				val &= MASK64(mb, 63 - sh);
15718c2ecf20Sopenharmony_ci				break;
15728c2ecf20Sopenharmony_ci			case 3:		/* rldimi */
15738c2ecf20Sopenharmony_ci				imm = MASK64(mb, 63 - sh);
15748c2ecf20Sopenharmony_ci				val = (regs->gpr[ra] & ~imm) |
15758c2ecf20Sopenharmony_ci					(val & imm);
15768c2ecf20Sopenharmony_ci			}
15778c2ecf20Sopenharmony_ci			op->val = val;
15788c2ecf20Sopenharmony_ci			goto logical_done;
15798c2ecf20Sopenharmony_ci		} else {
15808c2ecf20Sopenharmony_ci			sh = regs->gpr[rb] & 0x3f;
15818c2ecf20Sopenharmony_ci			val = ROTATE(val, sh);
15828c2ecf20Sopenharmony_ci			switch ((word >> 1) & 7) {
15838c2ecf20Sopenharmony_ci			case 0:		/* rldcl */
15848c2ecf20Sopenharmony_ci				op->val = val & MASK64_L(mb);
15858c2ecf20Sopenharmony_ci				goto logical_done;
15868c2ecf20Sopenharmony_ci			case 1:		/* rldcr */
15878c2ecf20Sopenharmony_ci				op->val = val & MASK64_R(mb);
15888c2ecf20Sopenharmony_ci				goto logical_done;
15898c2ecf20Sopenharmony_ci			}
15908c2ecf20Sopenharmony_ci		}
15918c2ecf20Sopenharmony_ci#endif
15928c2ecf20Sopenharmony_ci		op->type = UNKNOWN;	/* illegal instruction */
15938c2ecf20Sopenharmony_ci		return 0;
15948c2ecf20Sopenharmony_ci
15958c2ecf20Sopenharmony_ci	case 31:
15968c2ecf20Sopenharmony_ci		/* isel occupies 32 minor opcodes */
15978c2ecf20Sopenharmony_ci		if (((word >> 1) & 0x1f) == 15) {
15988c2ecf20Sopenharmony_ci			mb = (word >> 6) & 0x1f; /* bc field */
15998c2ecf20Sopenharmony_ci			val = (regs->ccr >> (31 - mb)) & 1;
16008c2ecf20Sopenharmony_ci			val2 = (ra) ? regs->gpr[ra] : 0;
16018c2ecf20Sopenharmony_ci
16028c2ecf20Sopenharmony_ci			op->val = (val) ? val2 : regs->gpr[rb];
16038c2ecf20Sopenharmony_ci			goto compute_done;
16048c2ecf20Sopenharmony_ci		}
16058c2ecf20Sopenharmony_ci
16068c2ecf20Sopenharmony_ci		switch ((word >> 1) & 0x3ff) {
16078c2ecf20Sopenharmony_ci		case 4:		/* tw */
16088c2ecf20Sopenharmony_ci			if (rd == 0x1f ||
16098c2ecf20Sopenharmony_ci			    (rd & trap_compare((int)regs->gpr[ra],
16108c2ecf20Sopenharmony_ci					       (int)regs->gpr[rb])))
16118c2ecf20Sopenharmony_ci				goto trap;
16128c2ecf20Sopenharmony_ci			return 1;
16138c2ecf20Sopenharmony_ci#ifdef __powerpc64__
16148c2ecf20Sopenharmony_ci		case 68:	/* td */
16158c2ecf20Sopenharmony_ci			if (rd & trap_compare(regs->gpr[ra], regs->gpr[rb]))
16168c2ecf20Sopenharmony_ci				goto trap;
16178c2ecf20Sopenharmony_ci			return 1;
16188c2ecf20Sopenharmony_ci#endif
16198c2ecf20Sopenharmony_ci		case 83:	/* mfmsr */
16208c2ecf20Sopenharmony_ci			if (regs->msr & MSR_PR)
16218c2ecf20Sopenharmony_ci				goto priv;
16228c2ecf20Sopenharmony_ci			op->type = MFMSR;
16238c2ecf20Sopenharmony_ci			op->reg = rd;
16248c2ecf20Sopenharmony_ci			return 0;
16258c2ecf20Sopenharmony_ci		case 146:	/* mtmsr */
16268c2ecf20Sopenharmony_ci			if (regs->msr & MSR_PR)
16278c2ecf20Sopenharmony_ci				goto priv;
16288c2ecf20Sopenharmony_ci			op->type = MTMSR;
16298c2ecf20Sopenharmony_ci			op->reg = rd;
16308c2ecf20Sopenharmony_ci			op->val = 0xffffffff & ~(MSR_ME | MSR_LE);
16318c2ecf20Sopenharmony_ci			return 0;
16328c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
16338c2ecf20Sopenharmony_ci		case 178:	/* mtmsrd */
16348c2ecf20Sopenharmony_ci			if (regs->msr & MSR_PR)
16358c2ecf20Sopenharmony_ci				goto priv;
16368c2ecf20Sopenharmony_ci			op->type = MTMSR;
16378c2ecf20Sopenharmony_ci			op->reg = rd;
16388c2ecf20Sopenharmony_ci			/* only MSR_EE and MSR_RI get changed if bit 15 set */
16398c2ecf20Sopenharmony_ci			/* mtmsrd doesn't change MSR_HV, MSR_ME or MSR_LE */
16408c2ecf20Sopenharmony_ci			imm = (word & 0x10000)? 0x8002: 0xefffffffffffeffeUL;
16418c2ecf20Sopenharmony_ci			op->val = imm;
16428c2ecf20Sopenharmony_ci			return 0;
16438c2ecf20Sopenharmony_ci#endif
16448c2ecf20Sopenharmony_ci
16458c2ecf20Sopenharmony_ci		case 19:	/* mfcr */
16468c2ecf20Sopenharmony_ci			imm = 0xffffffffUL;
16478c2ecf20Sopenharmony_ci			if ((word >> 20) & 1) {
16488c2ecf20Sopenharmony_ci				imm = 0xf0000000UL;
16498c2ecf20Sopenharmony_ci				for (sh = 0; sh < 8; ++sh) {
16508c2ecf20Sopenharmony_ci					if (word & (0x80000 >> sh))
16518c2ecf20Sopenharmony_ci						break;
16528c2ecf20Sopenharmony_ci					imm >>= 4;
16538c2ecf20Sopenharmony_ci				}
16548c2ecf20Sopenharmony_ci			}
16558c2ecf20Sopenharmony_ci			op->val = regs->ccr & imm;
16568c2ecf20Sopenharmony_ci			goto compute_done;
16578c2ecf20Sopenharmony_ci
16588c2ecf20Sopenharmony_ci		case 144:	/* mtcrf */
16598c2ecf20Sopenharmony_ci			op->type = COMPUTE + SETCC;
16608c2ecf20Sopenharmony_ci			imm = 0xf0000000UL;
16618c2ecf20Sopenharmony_ci			val = regs->gpr[rd];
16628c2ecf20Sopenharmony_ci			op->ccval = regs->ccr;
16638c2ecf20Sopenharmony_ci			for (sh = 0; sh < 8; ++sh) {
16648c2ecf20Sopenharmony_ci				if (word & (0x80000 >> sh))
16658c2ecf20Sopenharmony_ci					op->ccval = (op->ccval & ~imm) |
16668c2ecf20Sopenharmony_ci						(val & imm);
16678c2ecf20Sopenharmony_ci				imm >>= 4;
16688c2ecf20Sopenharmony_ci			}
16698c2ecf20Sopenharmony_ci			return 1;
16708c2ecf20Sopenharmony_ci
16718c2ecf20Sopenharmony_ci		case 339:	/* mfspr */
16728c2ecf20Sopenharmony_ci			spr = ((word >> 16) & 0x1f) | ((word >> 6) & 0x3e0);
16738c2ecf20Sopenharmony_ci			op->type = MFSPR;
16748c2ecf20Sopenharmony_ci			op->reg = rd;
16758c2ecf20Sopenharmony_ci			op->spr = spr;
16768c2ecf20Sopenharmony_ci			if (spr == SPRN_XER || spr == SPRN_LR ||
16778c2ecf20Sopenharmony_ci			    spr == SPRN_CTR)
16788c2ecf20Sopenharmony_ci				return 1;
16798c2ecf20Sopenharmony_ci			return 0;
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci		case 467:	/* mtspr */
16828c2ecf20Sopenharmony_ci			spr = ((word >> 16) & 0x1f) | ((word >> 6) & 0x3e0);
16838c2ecf20Sopenharmony_ci			op->type = MTSPR;
16848c2ecf20Sopenharmony_ci			op->val = regs->gpr[rd];
16858c2ecf20Sopenharmony_ci			op->spr = spr;
16868c2ecf20Sopenharmony_ci			if (spr == SPRN_XER || spr == SPRN_LR ||
16878c2ecf20Sopenharmony_ci			    spr == SPRN_CTR)
16888c2ecf20Sopenharmony_ci				return 1;
16898c2ecf20Sopenharmony_ci			return 0;
16908c2ecf20Sopenharmony_ci
16918c2ecf20Sopenharmony_ci/*
16928c2ecf20Sopenharmony_ci * Compare instructions
16938c2ecf20Sopenharmony_ci */
16948c2ecf20Sopenharmony_ci		case 0:	/* cmp */
16958c2ecf20Sopenharmony_ci			val = regs->gpr[ra];
16968c2ecf20Sopenharmony_ci			val2 = regs->gpr[rb];
16978c2ecf20Sopenharmony_ci#ifdef __powerpc64__
16988c2ecf20Sopenharmony_ci			if ((rd & 1) == 0) {
16998c2ecf20Sopenharmony_ci				/* word (32-bit) compare */
17008c2ecf20Sopenharmony_ci				val = (int) val;
17018c2ecf20Sopenharmony_ci				val2 = (int) val2;
17028c2ecf20Sopenharmony_ci			}
17038c2ecf20Sopenharmony_ci#endif
17048c2ecf20Sopenharmony_ci			do_cmp_signed(regs, op, val, val2, rd >> 2);
17058c2ecf20Sopenharmony_ci			return 1;
17068c2ecf20Sopenharmony_ci
17078c2ecf20Sopenharmony_ci		case 32:	/* cmpl */
17088c2ecf20Sopenharmony_ci			val = regs->gpr[ra];
17098c2ecf20Sopenharmony_ci			val2 = regs->gpr[rb];
17108c2ecf20Sopenharmony_ci#ifdef __powerpc64__
17118c2ecf20Sopenharmony_ci			if ((rd & 1) == 0) {
17128c2ecf20Sopenharmony_ci				/* word (32-bit) compare */
17138c2ecf20Sopenharmony_ci				val = (unsigned int) val;
17148c2ecf20Sopenharmony_ci				val2 = (unsigned int) val2;
17158c2ecf20Sopenharmony_ci			}
17168c2ecf20Sopenharmony_ci#endif
17178c2ecf20Sopenharmony_ci			do_cmp_unsigned(regs, op, val, val2, rd >> 2);
17188c2ecf20Sopenharmony_ci			return 1;
17198c2ecf20Sopenharmony_ci
17208c2ecf20Sopenharmony_ci		case 508: /* cmpb */
17218c2ecf20Sopenharmony_ci			do_cmpb(regs, op, regs->gpr[rd], regs->gpr[rb]);
17228c2ecf20Sopenharmony_ci			goto logical_done_nocc;
17238c2ecf20Sopenharmony_ci
17248c2ecf20Sopenharmony_ci/*
17258c2ecf20Sopenharmony_ci * Arithmetic instructions
17268c2ecf20Sopenharmony_ci */
17278c2ecf20Sopenharmony_ci		case 8:	/* subfc */
17288c2ecf20Sopenharmony_ci			add_with_carry(regs, op, rd, ~regs->gpr[ra],
17298c2ecf20Sopenharmony_ci				       regs->gpr[rb], 1);
17308c2ecf20Sopenharmony_ci			goto arith_done;
17318c2ecf20Sopenharmony_ci#ifdef __powerpc64__
17328c2ecf20Sopenharmony_ci		case 9:	/* mulhdu */
17338c2ecf20Sopenharmony_ci			asm("mulhdu %0,%1,%2" : "=r" (op->val) :
17348c2ecf20Sopenharmony_ci			    "r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
17358c2ecf20Sopenharmony_ci			goto arith_done;
17368c2ecf20Sopenharmony_ci#endif
17378c2ecf20Sopenharmony_ci		case 10:	/* addc */
17388c2ecf20Sopenharmony_ci			add_with_carry(regs, op, rd, regs->gpr[ra],
17398c2ecf20Sopenharmony_ci				       regs->gpr[rb], 0);
17408c2ecf20Sopenharmony_ci			goto arith_done;
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci		case 11:	/* mulhwu */
17438c2ecf20Sopenharmony_ci			asm("mulhwu %0,%1,%2" : "=r" (op->val) :
17448c2ecf20Sopenharmony_ci			    "r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
17458c2ecf20Sopenharmony_ci			goto arith_done;
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci		case 40:	/* subf */
17488c2ecf20Sopenharmony_ci			op->val = regs->gpr[rb] - regs->gpr[ra];
17498c2ecf20Sopenharmony_ci			goto arith_done;
17508c2ecf20Sopenharmony_ci#ifdef __powerpc64__
17518c2ecf20Sopenharmony_ci		case 73:	/* mulhd */
17528c2ecf20Sopenharmony_ci			asm("mulhd %0,%1,%2" : "=r" (op->val) :
17538c2ecf20Sopenharmony_ci			    "r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
17548c2ecf20Sopenharmony_ci			goto arith_done;
17558c2ecf20Sopenharmony_ci#endif
17568c2ecf20Sopenharmony_ci		case 75:	/* mulhw */
17578c2ecf20Sopenharmony_ci			asm("mulhw %0,%1,%2" : "=r" (op->val) :
17588c2ecf20Sopenharmony_ci			    "r" (regs->gpr[ra]), "r" (regs->gpr[rb]));
17598c2ecf20Sopenharmony_ci			goto arith_done;
17608c2ecf20Sopenharmony_ci
17618c2ecf20Sopenharmony_ci		case 104:	/* neg */
17628c2ecf20Sopenharmony_ci			op->val = -regs->gpr[ra];
17638c2ecf20Sopenharmony_ci			goto arith_done;
17648c2ecf20Sopenharmony_ci
17658c2ecf20Sopenharmony_ci		case 136:	/* subfe */
17668c2ecf20Sopenharmony_ci			add_with_carry(regs, op, rd, ~regs->gpr[ra],
17678c2ecf20Sopenharmony_ci				       regs->gpr[rb], regs->xer & XER_CA);
17688c2ecf20Sopenharmony_ci			goto arith_done;
17698c2ecf20Sopenharmony_ci
17708c2ecf20Sopenharmony_ci		case 138:	/* adde */
17718c2ecf20Sopenharmony_ci			add_with_carry(regs, op, rd, regs->gpr[ra],
17728c2ecf20Sopenharmony_ci				       regs->gpr[rb], regs->xer & XER_CA);
17738c2ecf20Sopenharmony_ci			goto arith_done;
17748c2ecf20Sopenharmony_ci
17758c2ecf20Sopenharmony_ci		case 200:	/* subfze */
17768c2ecf20Sopenharmony_ci			add_with_carry(regs, op, rd, ~regs->gpr[ra], 0L,
17778c2ecf20Sopenharmony_ci				       regs->xer & XER_CA);
17788c2ecf20Sopenharmony_ci			goto arith_done;
17798c2ecf20Sopenharmony_ci
17808c2ecf20Sopenharmony_ci		case 202:	/* addze */
17818c2ecf20Sopenharmony_ci			add_with_carry(regs, op, rd, regs->gpr[ra], 0L,
17828c2ecf20Sopenharmony_ci				       regs->xer & XER_CA);
17838c2ecf20Sopenharmony_ci			goto arith_done;
17848c2ecf20Sopenharmony_ci
17858c2ecf20Sopenharmony_ci		case 232:	/* subfme */
17868c2ecf20Sopenharmony_ci			add_with_carry(regs, op, rd, ~regs->gpr[ra], -1L,
17878c2ecf20Sopenharmony_ci				       regs->xer & XER_CA);
17888c2ecf20Sopenharmony_ci			goto arith_done;
17898c2ecf20Sopenharmony_ci#ifdef __powerpc64__
17908c2ecf20Sopenharmony_ci		case 233:	/* mulld */
17918c2ecf20Sopenharmony_ci			op->val = regs->gpr[ra] * regs->gpr[rb];
17928c2ecf20Sopenharmony_ci			goto arith_done;
17938c2ecf20Sopenharmony_ci#endif
17948c2ecf20Sopenharmony_ci		case 234:	/* addme */
17958c2ecf20Sopenharmony_ci			add_with_carry(regs, op, rd, regs->gpr[ra], -1L,
17968c2ecf20Sopenharmony_ci				       regs->xer & XER_CA);
17978c2ecf20Sopenharmony_ci			goto arith_done;
17988c2ecf20Sopenharmony_ci
17998c2ecf20Sopenharmony_ci		case 235:	/* mullw */
18008c2ecf20Sopenharmony_ci			op->val = (long)(int) regs->gpr[ra] *
18018c2ecf20Sopenharmony_ci				(int) regs->gpr[rb];
18028c2ecf20Sopenharmony_ci
18038c2ecf20Sopenharmony_ci			goto arith_done;
18048c2ecf20Sopenharmony_ci#ifdef __powerpc64__
18058c2ecf20Sopenharmony_ci		case 265:	/* modud */
18068c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
18078c2ecf20Sopenharmony_ci				goto unknown_opcode;
18088c2ecf20Sopenharmony_ci			op->val = regs->gpr[ra] % regs->gpr[rb];
18098c2ecf20Sopenharmony_ci			goto compute_done;
18108c2ecf20Sopenharmony_ci#endif
18118c2ecf20Sopenharmony_ci		case 266:	/* add */
18128c2ecf20Sopenharmony_ci			op->val = regs->gpr[ra] + regs->gpr[rb];
18138c2ecf20Sopenharmony_ci			goto arith_done;
18148c2ecf20Sopenharmony_ci
18158c2ecf20Sopenharmony_ci		case 267:	/* moduw */
18168c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
18178c2ecf20Sopenharmony_ci				goto unknown_opcode;
18188c2ecf20Sopenharmony_ci			op->val = (unsigned int) regs->gpr[ra] %
18198c2ecf20Sopenharmony_ci				(unsigned int) regs->gpr[rb];
18208c2ecf20Sopenharmony_ci			goto compute_done;
18218c2ecf20Sopenharmony_ci#ifdef __powerpc64__
18228c2ecf20Sopenharmony_ci		case 457:	/* divdu */
18238c2ecf20Sopenharmony_ci			op->val = regs->gpr[ra] / regs->gpr[rb];
18248c2ecf20Sopenharmony_ci			goto arith_done;
18258c2ecf20Sopenharmony_ci#endif
18268c2ecf20Sopenharmony_ci		case 459:	/* divwu */
18278c2ecf20Sopenharmony_ci			op->val = (unsigned int) regs->gpr[ra] /
18288c2ecf20Sopenharmony_ci				(unsigned int) regs->gpr[rb];
18298c2ecf20Sopenharmony_ci			goto arith_done;
18308c2ecf20Sopenharmony_ci#ifdef __powerpc64__
18318c2ecf20Sopenharmony_ci		case 489:	/* divd */
18328c2ecf20Sopenharmony_ci			op->val = (long int) regs->gpr[ra] /
18338c2ecf20Sopenharmony_ci				(long int) regs->gpr[rb];
18348c2ecf20Sopenharmony_ci			goto arith_done;
18358c2ecf20Sopenharmony_ci#endif
18368c2ecf20Sopenharmony_ci		case 491:	/* divw */
18378c2ecf20Sopenharmony_ci			op->val = (int) regs->gpr[ra] /
18388c2ecf20Sopenharmony_ci				(int) regs->gpr[rb];
18398c2ecf20Sopenharmony_ci			goto arith_done;
18408c2ecf20Sopenharmony_ci#ifdef __powerpc64__
18418c2ecf20Sopenharmony_ci		case 425:	/* divde[.] */
18428c2ecf20Sopenharmony_ci			asm volatile(PPC_DIVDE(%0, %1, %2) :
18438c2ecf20Sopenharmony_ci				"=r" (op->val) : "r" (regs->gpr[ra]),
18448c2ecf20Sopenharmony_ci				"r" (regs->gpr[rb]));
18458c2ecf20Sopenharmony_ci			goto arith_done;
18468c2ecf20Sopenharmony_ci		case 393:	/* divdeu[.] */
18478c2ecf20Sopenharmony_ci			asm volatile(PPC_DIVDEU(%0, %1, %2) :
18488c2ecf20Sopenharmony_ci				"=r" (op->val) : "r" (regs->gpr[ra]),
18498c2ecf20Sopenharmony_ci				"r" (regs->gpr[rb]));
18508c2ecf20Sopenharmony_ci			goto arith_done;
18518c2ecf20Sopenharmony_ci#endif
18528c2ecf20Sopenharmony_ci		case 755:	/* darn */
18538c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
18548c2ecf20Sopenharmony_ci				goto unknown_opcode;
18558c2ecf20Sopenharmony_ci			switch (ra & 0x3) {
18568c2ecf20Sopenharmony_ci			case 0:
18578c2ecf20Sopenharmony_ci				/* 32-bit conditioned */
18588c2ecf20Sopenharmony_ci				asm volatile(PPC_DARN(%0, 0) : "=r" (op->val));
18598c2ecf20Sopenharmony_ci				goto compute_done;
18608c2ecf20Sopenharmony_ci
18618c2ecf20Sopenharmony_ci			case 1:
18628c2ecf20Sopenharmony_ci				/* 64-bit conditioned */
18638c2ecf20Sopenharmony_ci				asm volatile(PPC_DARN(%0, 1) : "=r" (op->val));
18648c2ecf20Sopenharmony_ci				goto compute_done;
18658c2ecf20Sopenharmony_ci
18668c2ecf20Sopenharmony_ci			case 2:
18678c2ecf20Sopenharmony_ci				/* 64-bit raw */
18688c2ecf20Sopenharmony_ci				asm volatile(PPC_DARN(%0, 2) : "=r" (op->val));
18698c2ecf20Sopenharmony_ci				goto compute_done;
18708c2ecf20Sopenharmony_ci			}
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci			goto unknown_opcode;
18738c2ecf20Sopenharmony_ci#ifdef __powerpc64__
18748c2ecf20Sopenharmony_ci		case 777:	/* modsd */
18758c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
18768c2ecf20Sopenharmony_ci				goto unknown_opcode;
18778c2ecf20Sopenharmony_ci			op->val = (long int) regs->gpr[ra] %
18788c2ecf20Sopenharmony_ci				(long int) regs->gpr[rb];
18798c2ecf20Sopenharmony_ci			goto compute_done;
18808c2ecf20Sopenharmony_ci#endif
18818c2ecf20Sopenharmony_ci		case 779:	/* modsw */
18828c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
18838c2ecf20Sopenharmony_ci				goto unknown_opcode;
18848c2ecf20Sopenharmony_ci			op->val = (int) regs->gpr[ra] %
18858c2ecf20Sopenharmony_ci				(int) regs->gpr[rb];
18868c2ecf20Sopenharmony_ci			goto compute_done;
18878c2ecf20Sopenharmony_ci
18888c2ecf20Sopenharmony_ci
18898c2ecf20Sopenharmony_ci/*
18908c2ecf20Sopenharmony_ci * Logical instructions
18918c2ecf20Sopenharmony_ci */
18928c2ecf20Sopenharmony_ci		case 26:	/* cntlzw */
18938c2ecf20Sopenharmony_ci			val = (unsigned int) regs->gpr[rd];
18948c2ecf20Sopenharmony_ci			op->val = ( val ? __builtin_clz(val) : 32 );
18958c2ecf20Sopenharmony_ci			goto logical_done;
18968c2ecf20Sopenharmony_ci#ifdef __powerpc64__
18978c2ecf20Sopenharmony_ci		case 58:	/* cntlzd */
18988c2ecf20Sopenharmony_ci			val = regs->gpr[rd];
18998c2ecf20Sopenharmony_ci			op->val = ( val ? __builtin_clzl(val) : 64 );
19008c2ecf20Sopenharmony_ci			goto logical_done;
19018c2ecf20Sopenharmony_ci#endif
19028c2ecf20Sopenharmony_ci		case 28:	/* and */
19038c2ecf20Sopenharmony_ci			op->val = regs->gpr[rd] & regs->gpr[rb];
19048c2ecf20Sopenharmony_ci			goto logical_done;
19058c2ecf20Sopenharmony_ci
19068c2ecf20Sopenharmony_ci		case 60:	/* andc */
19078c2ecf20Sopenharmony_ci			op->val = regs->gpr[rd] & ~regs->gpr[rb];
19088c2ecf20Sopenharmony_ci			goto logical_done;
19098c2ecf20Sopenharmony_ci
19108c2ecf20Sopenharmony_ci		case 122:	/* popcntb */
19118c2ecf20Sopenharmony_ci			do_popcnt(regs, op, regs->gpr[rd], 8);
19128c2ecf20Sopenharmony_ci			goto logical_done_nocc;
19138c2ecf20Sopenharmony_ci
19148c2ecf20Sopenharmony_ci		case 124:	/* nor */
19158c2ecf20Sopenharmony_ci			op->val = ~(regs->gpr[rd] | regs->gpr[rb]);
19168c2ecf20Sopenharmony_ci			goto logical_done;
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci		case 154:	/* prtyw */
19198c2ecf20Sopenharmony_ci			do_prty(regs, op, regs->gpr[rd], 32);
19208c2ecf20Sopenharmony_ci			goto logical_done_nocc;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci		case 186:	/* prtyd */
19238c2ecf20Sopenharmony_ci			do_prty(regs, op, regs->gpr[rd], 64);
19248c2ecf20Sopenharmony_ci			goto logical_done_nocc;
19258c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
19268c2ecf20Sopenharmony_ci		case 252:	/* bpermd */
19278c2ecf20Sopenharmony_ci			do_bpermd(regs, op, regs->gpr[rd], regs->gpr[rb]);
19288c2ecf20Sopenharmony_ci			goto logical_done_nocc;
19298c2ecf20Sopenharmony_ci#endif
19308c2ecf20Sopenharmony_ci		case 284:	/* xor */
19318c2ecf20Sopenharmony_ci			op->val = ~(regs->gpr[rd] ^ regs->gpr[rb]);
19328c2ecf20Sopenharmony_ci			goto logical_done;
19338c2ecf20Sopenharmony_ci
19348c2ecf20Sopenharmony_ci		case 316:	/* xor */
19358c2ecf20Sopenharmony_ci			op->val = regs->gpr[rd] ^ regs->gpr[rb];
19368c2ecf20Sopenharmony_ci			goto logical_done;
19378c2ecf20Sopenharmony_ci
19388c2ecf20Sopenharmony_ci		case 378:	/* popcntw */
19398c2ecf20Sopenharmony_ci			do_popcnt(regs, op, regs->gpr[rd], 32);
19408c2ecf20Sopenharmony_ci			goto logical_done_nocc;
19418c2ecf20Sopenharmony_ci
19428c2ecf20Sopenharmony_ci		case 412:	/* orc */
19438c2ecf20Sopenharmony_ci			op->val = regs->gpr[rd] | ~regs->gpr[rb];
19448c2ecf20Sopenharmony_ci			goto logical_done;
19458c2ecf20Sopenharmony_ci
19468c2ecf20Sopenharmony_ci		case 444:	/* or */
19478c2ecf20Sopenharmony_ci			op->val = regs->gpr[rd] | regs->gpr[rb];
19488c2ecf20Sopenharmony_ci			goto logical_done;
19498c2ecf20Sopenharmony_ci
19508c2ecf20Sopenharmony_ci		case 476:	/* nand */
19518c2ecf20Sopenharmony_ci			op->val = ~(regs->gpr[rd] & regs->gpr[rb]);
19528c2ecf20Sopenharmony_ci			goto logical_done;
19538c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
19548c2ecf20Sopenharmony_ci		case 506:	/* popcntd */
19558c2ecf20Sopenharmony_ci			do_popcnt(regs, op, regs->gpr[rd], 64);
19568c2ecf20Sopenharmony_ci			goto logical_done_nocc;
19578c2ecf20Sopenharmony_ci#endif
19588c2ecf20Sopenharmony_ci		case 538:	/* cnttzw */
19598c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
19608c2ecf20Sopenharmony_ci				goto unknown_opcode;
19618c2ecf20Sopenharmony_ci			val = (unsigned int) regs->gpr[rd];
19628c2ecf20Sopenharmony_ci			op->val = (val ? __builtin_ctz(val) : 32);
19638c2ecf20Sopenharmony_ci			goto logical_done;
19648c2ecf20Sopenharmony_ci#ifdef __powerpc64__
19658c2ecf20Sopenharmony_ci		case 570:	/* cnttzd */
19668c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
19678c2ecf20Sopenharmony_ci				goto unknown_opcode;
19688c2ecf20Sopenharmony_ci			val = regs->gpr[rd];
19698c2ecf20Sopenharmony_ci			op->val = (val ? __builtin_ctzl(val) : 64);
19708c2ecf20Sopenharmony_ci			goto logical_done;
19718c2ecf20Sopenharmony_ci#endif
19728c2ecf20Sopenharmony_ci		case 922:	/* extsh */
19738c2ecf20Sopenharmony_ci			op->val = (signed short) regs->gpr[rd];
19748c2ecf20Sopenharmony_ci			goto logical_done;
19758c2ecf20Sopenharmony_ci
19768c2ecf20Sopenharmony_ci		case 954:	/* extsb */
19778c2ecf20Sopenharmony_ci			op->val = (signed char) regs->gpr[rd];
19788c2ecf20Sopenharmony_ci			goto logical_done;
19798c2ecf20Sopenharmony_ci#ifdef __powerpc64__
19808c2ecf20Sopenharmony_ci		case 986:	/* extsw */
19818c2ecf20Sopenharmony_ci			op->val = (signed int) regs->gpr[rd];
19828c2ecf20Sopenharmony_ci			goto logical_done;
19838c2ecf20Sopenharmony_ci#endif
19848c2ecf20Sopenharmony_ci
19858c2ecf20Sopenharmony_ci/*
19868c2ecf20Sopenharmony_ci * Shift instructions
19878c2ecf20Sopenharmony_ci */
19888c2ecf20Sopenharmony_ci		case 24:	/* slw */
19898c2ecf20Sopenharmony_ci			sh = regs->gpr[rb] & 0x3f;
19908c2ecf20Sopenharmony_ci			if (sh < 32)
19918c2ecf20Sopenharmony_ci				op->val = (regs->gpr[rd] << sh) & 0xffffffffUL;
19928c2ecf20Sopenharmony_ci			else
19938c2ecf20Sopenharmony_ci				op->val = 0;
19948c2ecf20Sopenharmony_ci			goto logical_done;
19958c2ecf20Sopenharmony_ci
19968c2ecf20Sopenharmony_ci		case 536:	/* srw */
19978c2ecf20Sopenharmony_ci			sh = regs->gpr[rb] & 0x3f;
19988c2ecf20Sopenharmony_ci			if (sh < 32)
19998c2ecf20Sopenharmony_ci				op->val = (regs->gpr[rd] & 0xffffffffUL) >> sh;
20008c2ecf20Sopenharmony_ci			else
20018c2ecf20Sopenharmony_ci				op->val = 0;
20028c2ecf20Sopenharmony_ci			goto logical_done;
20038c2ecf20Sopenharmony_ci
20048c2ecf20Sopenharmony_ci		case 792:	/* sraw */
20058c2ecf20Sopenharmony_ci			op->type = COMPUTE + SETREG + SETXER;
20068c2ecf20Sopenharmony_ci			sh = regs->gpr[rb] & 0x3f;
20078c2ecf20Sopenharmony_ci			ival = (signed int) regs->gpr[rd];
20088c2ecf20Sopenharmony_ci			op->val = ival >> (sh < 32 ? sh : 31);
20098c2ecf20Sopenharmony_ci			op->xerval = regs->xer;
20108c2ecf20Sopenharmony_ci			if (ival < 0 && (sh >= 32 || (ival & ((1ul << sh) - 1)) != 0))
20118c2ecf20Sopenharmony_ci				op->xerval |= XER_CA;
20128c2ecf20Sopenharmony_ci			else
20138c2ecf20Sopenharmony_ci				op->xerval &= ~XER_CA;
20148c2ecf20Sopenharmony_ci			set_ca32(op, op->xerval & XER_CA);
20158c2ecf20Sopenharmony_ci			goto logical_done;
20168c2ecf20Sopenharmony_ci
20178c2ecf20Sopenharmony_ci		case 824:	/* srawi */
20188c2ecf20Sopenharmony_ci			op->type = COMPUTE + SETREG + SETXER;
20198c2ecf20Sopenharmony_ci			sh = rb;
20208c2ecf20Sopenharmony_ci			ival = (signed int) regs->gpr[rd];
20218c2ecf20Sopenharmony_ci			op->val = ival >> sh;
20228c2ecf20Sopenharmony_ci			op->xerval = regs->xer;
20238c2ecf20Sopenharmony_ci			if (ival < 0 && (ival & ((1ul << sh) - 1)) != 0)
20248c2ecf20Sopenharmony_ci				op->xerval |= XER_CA;
20258c2ecf20Sopenharmony_ci			else
20268c2ecf20Sopenharmony_ci				op->xerval &= ~XER_CA;
20278c2ecf20Sopenharmony_ci			set_ca32(op, op->xerval & XER_CA);
20288c2ecf20Sopenharmony_ci			goto logical_done;
20298c2ecf20Sopenharmony_ci
20308c2ecf20Sopenharmony_ci#ifdef __powerpc64__
20318c2ecf20Sopenharmony_ci		case 27:	/* sld */
20328c2ecf20Sopenharmony_ci			sh = regs->gpr[rb] & 0x7f;
20338c2ecf20Sopenharmony_ci			if (sh < 64)
20348c2ecf20Sopenharmony_ci				op->val = regs->gpr[rd] << sh;
20358c2ecf20Sopenharmony_ci			else
20368c2ecf20Sopenharmony_ci				op->val = 0;
20378c2ecf20Sopenharmony_ci			goto logical_done;
20388c2ecf20Sopenharmony_ci
20398c2ecf20Sopenharmony_ci		case 539:	/* srd */
20408c2ecf20Sopenharmony_ci			sh = regs->gpr[rb] & 0x7f;
20418c2ecf20Sopenharmony_ci			if (sh < 64)
20428c2ecf20Sopenharmony_ci				op->val = regs->gpr[rd] >> sh;
20438c2ecf20Sopenharmony_ci			else
20448c2ecf20Sopenharmony_ci				op->val = 0;
20458c2ecf20Sopenharmony_ci			goto logical_done;
20468c2ecf20Sopenharmony_ci
20478c2ecf20Sopenharmony_ci		case 794:	/* srad */
20488c2ecf20Sopenharmony_ci			op->type = COMPUTE + SETREG + SETXER;
20498c2ecf20Sopenharmony_ci			sh = regs->gpr[rb] & 0x7f;
20508c2ecf20Sopenharmony_ci			ival = (signed long int) regs->gpr[rd];
20518c2ecf20Sopenharmony_ci			op->val = ival >> (sh < 64 ? sh : 63);
20528c2ecf20Sopenharmony_ci			op->xerval = regs->xer;
20538c2ecf20Sopenharmony_ci			if (ival < 0 && (sh >= 64 || (ival & ((1ul << sh) - 1)) != 0))
20548c2ecf20Sopenharmony_ci				op->xerval |= XER_CA;
20558c2ecf20Sopenharmony_ci			else
20568c2ecf20Sopenharmony_ci				op->xerval &= ~XER_CA;
20578c2ecf20Sopenharmony_ci			set_ca32(op, op->xerval & XER_CA);
20588c2ecf20Sopenharmony_ci			goto logical_done;
20598c2ecf20Sopenharmony_ci
20608c2ecf20Sopenharmony_ci		case 826:	/* sradi with sh_5 = 0 */
20618c2ecf20Sopenharmony_ci		case 827:	/* sradi with sh_5 = 1 */
20628c2ecf20Sopenharmony_ci			op->type = COMPUTE + SETREG + SETXER;
20638c2ecf20Sopenharmony_ci			sh = rb | ((word & 2) << 4);
20648c2ecf20Sopenharmony_ci			ival = (signed long int) regs->gpr[rd];
20658c2ecf20Sopenharmony_ci			op->val = ival >> sh;
20668c2ecf20Sopenharmony_ci			op->xerval = regs->xer;
20678c2ecf20Sopenharmony_ci			if (ival < 0 && (ival & ((1ul << sh) - 1)) != 0)
20688c2ecf20Sopenharmony_ci				op->xerval |= XER_CA;
20698c2ecf20Sopenharmony_ci			else
20708c2ecf20Sopenharmony_ci				op->xerval &= ~XER_CA;
20718c2ecf20Sopenharmony_ci			set_ca32(op, op->xerval & XER_CA);
20728c2ecf20Sopenharmony_ci			goto logical_done;
20738c2ecf20Sopenharmony_ci
20748c2ecf20Sopenharmony_ci		case 890:	/* extswsli with sh_5 = 0 */
20758c2ecf20Sopenharmony_ci		case 891:	/* extswsli with sh_5 = 1 */
20768c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
20778c2ecf20Sopenharmony_ci				goto unknown_opcode;
20788c2ecf20Sopenharmony_ci			op->type = COMPUTE + SETREG;
20798c2ecf20Sopenharmony_ci			sh = rb | ((word & 2) << 4);
20808c2ecf20Sopenharmony_ci			val = (signed int) regs->gpr[rd];
20818c2ecf20Sopenharmony_ci			if (sh)
20828c2ecf20Sopenharmony_ci				op->val = ROTATE(val, sh) & MASK64(0, 63 - sh);
20838c2ecf20Sopenharmony_ci			else
20848c2ecf20Sopenharmony_ci				op->val = val;
20858c2ecf20Sopenharmony_ci			goto logical_done;
20868c2ecf20Sopenharmony_ci
20878c2ecf20Sopenharmony_ci#endif /* __powerpc64__ */
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci/*
20908c2ecf20Sopenharmony_ci * Cache instructions
20918c2ecf20Sopenharmony_ci */
20928c2ecf20Sopenharmony_ci		case 54:	/* dcbst */
20938c2ecf20Sopenharmony_ci			op->type = MKOP(CACHEOP, DCBST, 0);
20948c2ecf20Sopenharmony_ci			op->ea = xform_ea(word, regs);
20958c2ecf20Sopenharmony_ci			return 0;
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci		case 86:	/* dcbf */
20988c2ecf20Sopenharmony_ci			op->type = MKOP(CACHEOP, DCBF, 0);
20998c2ecf20Sopenharmony_ci			op->ea = xform_ea(word, regs);
21008c2ecf20Sopenharmony_ci			return 0;
21018c2ecf20Sopenharmony_ci
21028c2ecf20Sopenharmony_ci		case 246:	/* dcbtst */
21038c2ecf20Sopenharmony_ci			op->type = MKOP(CACHEOP, DCBTST, 0);
21048c2ecf20Sopenharmony_ci			op->ea = xform_ea(word, regs);
21058c2ecf20Sopenharmony_ci			op->reg = rd;
21068c2ecf20Sopenharmony_ci			return 0;
21078c2ecf20Sopenharmony_ci
21088c2ecf20Sopenharmony_ci		case 278:	/* dcbt */
21098c2ecf20Sopenharmony_ci			op->type = MKOP(CACHEOP, DCBTST, 0);
21108c2ecf20Sopenharmony_ci			op->ea = xform_ea(word, regs);
21118c2ecf20Sopenharmony_ci			op->reg = rd;
21128c2ecf20Sopenharmony_ci			return 0;
21138c2ecf20Sopenharmony_ci
21148c2ecf20Sopenharmony_ci		case 982:	/* icbi */
21158c2ecf20Sopenharmony_ci			op->type = MKOP(CACHEOP, ICBI, 0);
21168c2ecf20Sopenharmony_ci			op->ea = xform_ea(word, regs);
21178c2ecf20Sopenharmony_ci			return 0;
21188c2ecf20Sopenharmony_ci
21198c2ecf20Sopenharmony_ci		case 1014:	/* dcbz */
21208c2ecf20Sopenharmony_ci			op->type = MKOP(CACHEOP, DCBZ, 0);
21218c2ecf20Sopenharmony_ci			op->ea = xform_ea(word, regs);
21228c2ecf20Sopenharmony_ci			return 0;
21238c2ecf20Sopenharmony_ci		}
21248c2ecf20Sopenharmony_ci		break;
21258c2ecf20Sopenharmony_ci	}
21268c2ecf20Sopenharmony_ci
21278c2ecf20Sopenharmony_ci/*
21288c2ecf20Sopenharmony_ci * Loads and stores.
21298c2ecf20Sopenharmony_ci */
21308c2ecf20Sopenharmony_ci	op->type = UNKNOWN;
21318c2ecf20Sopenharmony_ci	op->update_reg = ra;
21328c2ecf20Sopenharmony_ci	op->reg = rd;
21338c2ecf20Sopenharmony_ci	op->val = regs->gpr[rd];
21348c2ecf20Sopenharmony_ci	u = (word >> 20) & UPDATE;
21358c2ecf20Sopenharmony_ci	op->vsx_flags = 0;
21368c2ecf20Sopenharmony_ci
21378c2ecf20Sopenharmony_ci	switch (opcode) {
21388c2ecf20Sopenharmony_ci	case 31:
21398c2ecf20Sopenharmony_ci		u = word & UPDATE;
21408c2ecf20Sopenharmony_ci		op->ea = xform_ea(word, regs);
21418c2ecf20Sopenharmony_ci		switch ((word >> 1) & 0x3ff) {
21428c2ecf20Sopenharmony_ci		case 20:	/* lwarx */
21438c2ecf20Sopenharmony_ci			op->type = MKOP(LARX, 0, 4);
21448c2ecf20Sopenharmony_ci			break;
21458c2ecf20Sopenharmony_ci
21468c2ecf20Sopenharmony_ci		case 150:	/* stwcx. */
21478c2ecf20Sopenharmony_ci			op->type = MKOP(STCX, 0, 4);
21488c2ecf20Sopenharmony_ci			break;
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_ci#ifdef __powerpc64__
21518c2ecf20Sopenharmony_ci		case 84:	/* ldarx */
21528c2ecf20Sopenharmony_ci			op->type = MKOP(LARX, 0, 8);
21538c2ecf20Sopenharmony_ci			break;
21548c2ecf20Sopenharmony_ci
21558c2ecf20Sopenharmony_ci		case 214:	/* stdcx. */
21568c2ecf20Sopenharmony_ci			op->type = MKOP(STCX, 0, 8);
21578c2ecf20Sopenharmony_ci			break;
21588c2ecf20Sopenharmony_ci
21598c2ecf20Sopenharmony_ci		case 52:	/* lbarx */
21608c2ecf20Sopenharmony_ci			op->type = MKOP(LARX, 0, 1);
21618c2ecf20Sopenharmony_ci			break;
21628c2ecf20Sopenharmony_ci
21638c2ecf20Sopenharmony_ci		case 694:	/* stbcx. */
21648c2ecf20Sopenharmony_ci			op->type = MKOP(STCX, 0, 1);
21658c2ecf20Sopenharmony_ci			break;
21668c2ecf20Sopenharmony_ci
21678c2ecf20Sopenharmony_ci		case 116:	/* lharx */
21688c2ecf20Sopenharmony_ci			op->type = MKOP(LARX, 0, 2);
21698c2ecf20Sopenharmony_ci			break;
21708c2ecf20Sopenharmony_ci
21718c2ecf20Sopenharmony_ci		case 726:	/* sthcx. */
21728c2ecf20Sopenharmony_ci			op->type = MKOP(STCX, 0, 2);
21738c2ecf20Sopenharmony_ci			break;
21748c2ecf20Sopenharmony_ci
21758c2ecf20Sopenharmony_ci		case 276:	/* lqarx */
21768c2ecf20Sopenharmony_ci			if (!((rd & 1) || rd == ra || rd == rb))
21778c2ecf20Sopenharmony_ci				op->type = MKOP(LARX, 0, 16);
21788c2ecf20Sopenharmony_ci			break;
21798c2ecf20Sopenharmony_ci
21808c2ecf20Sopenharmony_ci		case 182:	/* stqcx. */
21818c2ecf20Sopenharmony_ci			if (!(rd & 1))
21828c2ecf20Sopenharmony_ci				op->type = MKOP(STCX, 0, 16);
21838c2ecf20Sopenharmony_ci			break;
21848c2ecf20Sopenharmony_ci#endif
21858c2ecf20Sopenharmony_ci
21868c2ecf20Sopenharmony_ci		case 23:	/* lwzx */
21878c2ecf20Sopenharmony_ci		case 55:	/* lwzux */
21888c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, u, 4);
21898c2ecf20Sopenharmony_ci			break;
21908c2ecf20Sopenharmony_ci
21918c2ecf20Sopenharmony_ci		case 87:	/* lbzx */
21928c2ecf20Sopenharmony_ci		case 119:	/* lbzux */
21938c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, u, 1);
21948c2ecf20Sopenharmony_ci			break;
21958c2ecf20Sopenharmony_ci
21968c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC
21978c2ecf20Sopenharmony_ci		/*
21988c2ecf20Sopenharmony_ci		 * Note: for the load/store vector element instructions,
21998c2ecf20Sopenharmony_ci		 * bits of the EA say which field of the VMX register to use.
22008c2ecf20Sopenharmony_ci		 */
22018c2ecf20Sopenharmony_ci		case 7:		/* lvebx */
22028c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VMX, 0, 1);
22038c2ecf20Sopenharmony_ci			op->element_size = 1;
22048c2ecf20Sopenharmony_ci			break;
22058c2ecf20Sopenharmony_ci
22068c2ecf20Sopenharmony_ci		case 39:	/* lvehx */
22078c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VMX, 0, 2);
22088c2ecf20Sopenharmony_ci			op->element_size = 2;
22098c2ecf20Sopenharmony_ci			break;
22108c2ecf20Sopenharmony_ci
22118c2ecf20Sopenharmony_ci		case 71:	/* lvewx */
22128c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VMX, 0, 4);
22138c2ecf20Sopenharmony_ci			op->element_size = 4;
22148c2ecf20Sopenharmony_ci			break;
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci		case 103:	/* lvx */
22178c2ecf20Sopenharmony_ci		case 359:	/* lvxl */
22188c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VMX, 0, 16);
22198c2ecf20Sopenharmony_ci			op->element_size = 16;
22208c2ecf20Sopenharmony_ci			break;
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci		case 135:	/* stvebx */
22238c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VMX, 0, 1);
22248c2ecf20Sopenharmony_ci			op->element_size = 1;
22258c2ecf20Sopenharmony_ci			break;
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_ci		case 167:	/* stvehx */
22288c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VMX, 0, 2);
22298c2ecf20Sopenharmony_ci			op->element_size = 2;
22308c2ecf20Sopenharmony_ci			break;
22318c2ecf20Sopenharmony_ci
22328c2ecf20Sopenharmony_ci		case 199:	/* stvewx */
22338c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VMX, 0, 4);
22348c2ecf20Sopenharmony_ci			op->element_size = 4;
22358c2ecf20Sopenharmony_ci			break;
22368c2ecf20Sopenharmony_ci
22378c2ecf20Sopenharmony_ci		case 231:	/* stvx */
22388c2ecf20Sopenharmony_ci		case 487:	/* stvxl */
22398c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VMX, 0, 16);
22408c2ecf20Sopenharmony_ci			break;
22418c2ecf20Sopenharmony_ci#endif /* CONFIG_ALTIVEC */
22428c2ecf20Sopenharmony_ci
22438c2ecf20Sopenharmony_ci#ifdef __powerpc64__
22448c2ecf20Sopenharmony_ci		case 21:	/* ldx */
22458c2ecf20Sopenharmony_ci		case 53:	/* ldux */
22468c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, u, 8);
22478c2ecf20Sopenharmony_ci			break;
22488c2ecf20Sopenharmony_ci
22498c2ecf20Sopenharmony_ci		case 149:	/* stdx */
22508c2ecf20Sopenharmony_ci		case 181:	/* stdux */
22518c2ecf20Sopenharmony_ci			op->type = MKOP(STORE, u, 8);
22528c2ecf20Sopenharmony_ci			break;
22538c2ecf20Sopenharmony_ci#endif
22548c2ecf20Sopenharmony_ci
22558c2ecf20Sopenharmony_ci		case 151:	/* stwx */
22568c2ecf20Sopenharmony_ci		case 183:	/* stwux */
22578c2ecf20Sopenharmony_ci			op->type = MKOP(STORE, u, 4);
22588c2ecf20Sopenharmony_ci			break;
22598c2ecf20Sopenharmony_ci
22608c2ecf20Sopenharmony_ci		case 215:	/* stbx */
22618c2ecf20Sopenharmony_ci		case 247:	/* stbux */
22628c2ecf20Sopenharmony_ci			op->type = MKOP(STORE, u, 1);
22638c2ecf20Sopenharmony_ci			break;
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci		case 279:	/* lhzx */
22668c2ecf20Sopenharmony_ci		case 311:	/* lhzux */
22678c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, u, 2);
22688c2ecf20Sopenharmony_ci			break;
22698c2ecf20Sopenharmony_ci
22708c2ecf20Sopenharmony_ci#ifdef __powerpc64__
22718c2ecf20Sopenharmony_ci		case 341:	/* lwax */
22728c2ecf20Sopenharmony_ci		case 373:	/* lwaux */
22738c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, SIGNEXT | u, 4);
22748c2ecf20Sopenharmony_ci			break;
22758c2ecf20Sopenharmony_ci#endif
22768c2ecf20Sopenharmony_ci
22778c2ecf20Sopenharmony_ci		case 343:	/* lhax */
22788c2ecf20Sopenharmony_ci		case 375:	/* lhaux */
22798c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, SIGNEXT | u, 2);
22808c2ecf20Sopenharmony_ci			break;
22818c2ecf20Sopenharmony_ci
22828c2ecf20Sopenharmony_ci		case 407:	/* sthx */
22838c2ecf20Sopenharmony_ci		case 439:	/* sthux */
22848c2ecf20Sopenharmony_ci			op->type = MKOP(STORE, u, 2);
22858c2ecf20Sopenharmony_ci			break;
22868c2ecf20Sopenharmony_ci
22878c2ecf20Sopenharmony_ci#ifdef __powerpc64__
22888c2ecf20Sopenharmony_ci		case 532:	/* ldbrx */
22898c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, BYTEREV, 8);
22908c2ecf20Sopenharmony_ci			break;
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_ci#endif
22938c2ecf20Sopenharmony_ci		case 533:	/* lswx */
22948c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_MULTI, 0, regs->xer & 0x7f);
22958c2ecf20Sopenharmony_ci			break;
22968c2ecf20Sopenharmony_ci
22978c2ecf20Sopenharmony_ci		case 534:	/* lwbrx */
22988c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, BYTEREV, 4);
22998c2ecf20Sopenharmony_ci			break;
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_ci		case 597:	/* lswi */
23028c2ecf20Sopenharmony_ci			if (rb == 0)
23038c2ecf20Sopenharmony_ci				rb = 32;	/* # bytes to load */
23048c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_MULTI, 0, rb);
23058c2ecf20Sopenharmony_ci			op->ea = ra ? regs->gpr[ra] : 0;
23068c2ecf20Sopenharmony_ci			break;
23078c2ecf20Sopenharmony_ci
23088c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_FPU
23098c2ecf20Sopenharmony_ci		case 535:	/* lfsx */
23108c2ecf20Sopenharmony_ci		case 567:	/* lfsux */
23118c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_FP, u | FPCONV, 4);
23128c2ecf20Sopenharmony_ci			break;
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci		case 599:	/* lfdx */
23158c2ecf20Sopenharmony_ci		case 631:	/* lfdux */
23168c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_FP, u, 8);
23178c2ecf20Sopenharmony_ci			break;
23188c2ecf20Sopenharmony_ci
23198c2ecf20Sopenharmony_ci		case 663:	/* stfsx */
23208c2ecf20Sopenharmony_ci		case 695:	/* stfsux */
23218c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_FP, u | FPCONV, 4);
23228c2ecf20Sopenharmony_ci			break;
23238c2ecf20Sopenharmony_ci
23248c2ecf20Sopenharmony_ci		case 727:	/* stfdx */
23258c2ecf20Sopenharmony_ci		case 759:	/* stfdux */
23268c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_FP, u, 8);
23278c2ecf20Sopenharmony_ci			break;
23288c2ecf20Sopenharmony_ci
23298c2ecf20Sopenharmony_ci#ifdef __powerpc64__
23308c2ecf20Sopenharmony_ci		case 791:	/* lfdpx */
23318c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_FP, 0, 16);
23328c2ecf20Sopenharmony_ci			break;
23338c2ecf20Sopenharmony_ci
23348c2ecf20Sopenharmony_ci		case 855:	/* lfiwax */
23358c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_FP, SIGNEXT, 4);
23368c2ecf20Sopenharmony_ci			break;
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci		case 887:	/* lfiwzx */
23398c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_FP, 0, 4);
23408c2ecf20Sopenharmony_ci			break;
23418c2ecf20Sopenharmony_ci
23428c2ecf20Sopenharmony_ci		case 919:	/* stfdpx */
23438c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_FP, 0, 16);
23448c2ecf20Sopenharmony_ci			break;
23458c2ecf20Sopenharmony_ci
23468c2ecf20Sopenharmony_ci		case 983:	/* stfiwx */
23478c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_FP, 0, 4);
23488c2ecf20Sopenharmony_ci			break;
23498c2ecf20Sopenharmony_ci#endif /* __powerpc64 */
23508c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC_FPU */
23518c2ecf20Sopenharmony_ci
23528c2ecf20Sopenharmony_ci#ifdef __powerpc64__
23538c2ecf20Sopenharmony_ci		case 660:	/* stdbrx */
23548c2ecf20Sopenharmony_ci			op->type = MKOP(STORE, BYTEREV, 8);
23558c2ecf20Sopenharmony_ci			op->val = byterev_8(regs->gpr[rd]);
23568c2ecf20Sopenharmony_ci			break;
23578c2ecf20Sopenharmony_ci
23588c2ecf20Sopenharmony_ci#endif
23598c2ecf20Sopenharmony_ci		case 661:	/* stswx */
23608c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_MULTI, 0, regs->xer & 0x7f);
23618c2ecf20Sopenharmony_ci			break;
23628c2ecf20Sopenharmony_ci
23638c2ecf20Sopenharmony_ci		case 662:	/* stwbrx */
23648c2ecf20Sopenharmony_ci			op->type = MKOP(STORE, BYTEREV, 4);
23658c2ecf20Sopenharmony_ci			op->val = byterev_4(regs->gpr[rd]);
23668c2ecf20Sopenharmony_ci			break;
23678c2ecf20Sopenharmony_ci
23688c2ecf20Sopenharmony_ci		case 725:	/* stswi */
23698c2ecf20Sopenharmony_ci			if (rb == 0)
23708c2ecf20Sopenharmony_ci				rb = 32;	/* # bytes to store */
23718c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_MULTI, 0, rb);
23728c2ecf20Sopenharmony_ci			op->ea = ra ? regs->gpr[ra] : 0;
23738c2ecf20Sopenharmony_ci			break;
23748c2ecf20Sopenharmony_ci
23758c2ecf20Sopenharmony_ci		case 790:	/* lhbrx */
23768c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, BYTEREV, 2);
23778c2ecf20Sopenharmony_ci			break;
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci		case 918:	/* sthbrx */
23808c2ecf20Sopenharmony_ci			op->type = MKOP(STORE, BYTEREV, 2);
23818c2ecf20Sopenharmony_ci			op->val = byterev_2(regs->gpr[rd]);
23828c2ecf20Sopenharmony_ci			break;
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX
23858c2ecf20Sopenharmony_ci		case 12:	/* lxsiwzx */
23868c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
23878c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 4);
23888c2ecf20Sopenharmony_ci			op->element_size = 8;
23898c2ecf20Sopenharmony_ci			break;
23908c2ecf20Sopenharmony_ci
23918c2ecf20Sopenharmony_ci		case 76:	/* lxsiwax */
23928c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
23938c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, SIGNEXT, 4);
23948c2ecf20Sopenharmony_ci			op->element_size = 8;
23958c2ecf20Sopenharmony_ci			break;
23968c2ecf20Sopenharmony_ci
23978c2ecf20Sopenharmony_ci		case 140:	/* stxsiwx */
23988c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
23998c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 4);
24008c2ecf20Sopenharmony_ci			op->element_size = 8;
24018c2ecf20Sopenharmony_ci			break;
24028c2ecf20Sopenharmony_ci
24038c2ecf20Sopenharmony_ci		case 268:	/* lxvx */
24048c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
24058c2ecf20Sopenharmony_ci				goto unknown_opcode;
24068c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24078c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 16);
24088c2ecf20Sopenharmony_ci			op->element_size = 16;
24098c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
24108c2ecf20Sopenharmony_ci			break;
24118c2ecf20Sopenharmony_ci
24128c2ecf20Sopenharmony_ci		case 269:	/* lxvl */
24138c2ecf20Sopenharmony_ci		case 301: {	/* lxvll */
24148c2ecf20Sopenharmony_ci			int nb;
24158c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
24168c2ecf20Sopenharmony_ci				goto unknown_opcode;
24178c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24188c2ecf20Sopenharmony_ci			op->ea = ra ? regs->gpr[ra] : 0;
24198c2ecf20Sopenharmony_ci			nb = regs->gpr[rb] & 0xff;
24208c2ecf20Sopenharmony_ci			if (nb > 16)
24218c2ecf20Sopenharmony_ci				nb = 16;
24228c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, nb);
24238c2ecf20Sopenharmony_ci			op->element_size = 16;
24248c2ecf20Sopenharmony_ci			op->vsx_flags = ((word & 0x20) ? VSX_LDLEFT : 0) |
24258c2ecf20Sopenharmony_ci				VSX_CHECK_VEC;
24268c2ecf20Sopenharmony_ci			break;
24278c2ecf20Sopenharmony_ci		}
24288c2ecf20Sopenharmony_ci		case 332:	/* lxvdsx */
24298c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24308c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 8);
24318c2ecf20Sopenharmony_ci			op->element_size = 8;
24328c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_SPLAT;
24338c2ecf20Sopenharmony_ci			break;
24348c2ecf20Sopenharmony_ci
24358c2ecf20Sopenharmony_ci		case 364:	/* lxvwsx */
24368c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
24378c2ecf20Sopenharmony_ci				goto unknown_opcode;
24388c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24398c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 4);
24408c2ecf20Sopenharmony_ci			op->element_size = 4;
24418c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_SPLAT | VSX_CHECK_VEC;
24428c2ecf20Sopenharmony_ci			break;
24438c2ecf20Sopenharmony_ci
24448c2ecf20Sopenharmony_ci		case 396:	/* stxvx */
24458c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
24468c2ecf20Sopenharmony_ci				goto unknown_opcode;
24478c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24488c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 16);
24498c2ecf20Sopenharmony_ci			op->element_size = 16;
24508c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
24518c2ecf20Sopenharmony_ci			break;
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci		case 397:	/* stxvl */
24548c2ecf20Sopenharmony_ci		case 429: {	/* stxvll */
24558c2ecf20Sopenharmony_ci			int nb;
24568c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
24578c2ecf20Sopenharmony_ci				goto unknown_opcode;
24588c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24598c2ecf20Sopenharmony_ci			op->ea = ra ? regs->gpr[ra] : 0;
24608c2ecf20Sopenharmony_ci			nb = regs->gpr[rb] & 0xff;
24618c2ecf20Sopenharmony_ci			if (nb > 16)
24628c2ecf20Sopenharmony_ci				nb = 16;
24638c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, nb);
24648c2ecf20Sopenharmony_ci			op->element_size = 16;
24658c2ecf20Sopenharmony_ci			op->vsx_flags = ((word & 0x20) ? VSX_LDLEFT : 0) |
24668c2ecf20Sopenharmony_ci				VSX_CHECK_VEC;
24678c2ecf20Sopenharmony_ci			break;
24688c2ecf20Sopenharmony_ci		}
24698c2ecf20Sopenharmony_ci		case 524:	/* lxsspx */
24708c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24718c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 4);
24728c2ecf20Sopenharmony_ci			op->element_size = 8;
24738c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_FPCONV;
24748c2ecf20Sopenharmony_ci			break;
24758c2ecf20Sopenharmony_ci
24768c2ecf20Sopenharmony_ci		case 588:	/* lxsdx */
24778c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24788c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 8);
24798c2ecf20Sopenharmony_ci			op->element_size = 8;
24808c2ecf20Sopenharmony_ci			break;
24818c2ecf20Sopenharmony_ci
24828c2ecf20Sopenharmony_ci		case 652:	/* stxsspx */
24838c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24848c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 4);
24858c2ecf20Sopenharmony_ci			op->element_size = 8;
24868c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_FPCONV;
24878c2ecf20Sopenharmony_ci			break;
24888c2ecf20Sopenharmony_ci
24898c2ecf20Sopenharmony_ci		case 716:	/* stxsdx */
24908c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24918c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 8);
24928c2ecf20Sopenharmony_ci			op->element_size = 8;
24938c2ecf20Sopenharmony_ci			break;
24948c2ecf20Sopenharmony_ci
24958c2ecf20Sopenharmony_ci		case 780:	/* lxvw4x */
24968c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
24978c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 16);
24988c2ecf20Sopenharmony_ci			op->element_size = 4;
24998c2ecf20Sopenharmony_ci			break;
25008c2ecf20Sopenharmony_ci
25018c2ecf20Sopenharmony_ci		case 781:	/* lxsibzx */
25028c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
25038c2ecf20Sopenharmony_ci				goto unknown_opcode;
25048c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25058c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 1);
25068c2ecf20Sopenharmony_ci			op->element_size = 8;
25078c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
25088c2ecf20Sopenharmony_ci			break;
25098c2ecf20Sopenharmony_ci
25108c2ecf20Sopenharmony_ci		case 812:	/* lxvh8x */
25118c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
25128c2ecf20Sopenharmony_ci				goto unknown_opcode;
25138c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25148c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 16);
25158c2ecf20Sopenharmony_ci			op->element_size = 2;
25168c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
25178c2ecf20Sopenharmony_ci			break;
25188c2ecf20Sopenharmony_ci
25198c2ecf20Sopenharmony_ci		case 813:	/* lxsihzx */
25208c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
25218c2ecf20Sopenharmony_ci				goto unknown_opcode;
25228c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25238c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 2);
25248c2ecf20Sopenharmony_ci			op->element_size = 8;
25258c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
25268c2ecf20Sopenharmony_ci			break;
25278c2ecf20Sopenharmony_ci
25288c2ecf20Sopenharmony_ci		case 844:	/* lxvd2x */
25298c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25308c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 16);
25318c2ecf20Sopenharmony_ci			op->element_size = 8;
25328c2ecf20Sopenharmony_ci			break;
25338c2ecf20Sopenharmony_ci
25348c2ecf20Sopenharmony_ci		case 876:	/* lxvb16x */
25358c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
25368c2ecf20Sopenharmony_ci				goto unknown_opcode;
25378c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25388c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 16);
25398c2ecf20Sopenharmony_ci			op->element_size = 1;
25408c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
25418c2ecf20Sopenharmony_ci			break;
25428c2ecf20Sopenharmony_ci
25438c2ecf20Sopenharmony_ci		case 908:	/* stxvw4x */
25448c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25458c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 16);
25468c2ecf20Sopenharmony_ci			op->element_size = 4;
25478c2ecf20Sopenharmony_ci			break;
25488c2ecf20Sopenharmony_ci
25498c2ecf20Sopenharmony_ci		case 909:	/* stxsibx */
25508c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
25518c2ecf20Sopenharmony_ci				goto unknown_opcode;
25528c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25538c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 1);
25548c2ecf20Sopenharmony_ci			op->element_size = 8;
25558c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
25568c2ecf20Sopenharmony_ci			break;
25578c2ecf20Sopenharmony_ci
25588c2ecf20Sopenharmony_ci		case 940:	/* stxvh8x */
25598c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
25608c2ecf20Sopenharmony_ci				goto unknown_opcode;
25618c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25628c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 16);
25638c2ecf20Sopenharmony_ci			op->element_size = 2;
25648c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
25658c2ecf20Sopenharmony_ci			break;
25668c2ecf20Sopenharmony_ci
25678c2ecf20Sopenharmony_ci		case 941:	/* stxsihx */
25688c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
25698c2ecf20Sopenharmony_ci				goto unknown_opcode;
25708c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25718c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 2);
25728c2ecf20Sopenharmony_ci			op->element_size = 8;
25738c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
25748c2ecf20Sopenharmony_ci			break;
25758c2ecf20Sopenharmony_ci
25768c2ecf20Sopenharmony_ci		case 972:	/* stxvd2x */
25778c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25788c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 16);
25798c2ecf20Sopenharmony_ci			op->element_size = 8;
25808c2ecf20Sopenharmony_ci			break;
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci		case 1004:	/* stxvb16x */
25838c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
25848c2ecf20Sopenharmony_ci				goto unknown_opcode;
25858c2ecf20Sopenharmony_ci			op->reg = rd | ((word & 1) << 5);
25868c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 16);
25878c2ecf20Sopenharmony_ci			op->element_size = 1;
25888c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
25898c2ecf20Sopenharmony_ci			break;
25908c2ecf20Sopenharmony_ci
25918c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */
25928c2ecf20Sopenharmony_ci		}
25938c2ecf20Sopenharmony_ci		break;
25948c2ecf20Sopenharmony_ci
25958c2ecf20Sopenharmony_ci	case 32:	/* lwz */
25968c2ecf20Sopenharmony_ci	case 33:	/* lwzu */
25978c2ecf20Sopenharmony_ci		op->type = MKOP(LOAD, u, 4);
25988c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
25998c2ecf20Sopenharmony_ci		break;
26008c2ecf20Sopenharmony_ci
26018c2ecf20Sopenharmony_ci	case 34:	/* lbz */
26028c2ecf20Sopenharmony_ci	case 35:	/* lbzu */
26038c2ecf20Sopenharmony_ci		op->type = MKOP(LOAD, u, 1);
26048c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26058c2ecf20Sopenharmony_ci		break;
26068c2ecf20Sopenharmony_ci
26078c2ecf20Sopenharmony_ci	case 36:	/* stw */
26088c2ecf20Sopenharmony_ci	case 37:	/* stwu */
26098c2ecf20Sopenharmony_ci		op->type = MKOP(STORE, u, 4);
26108c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26118c2ecf20Sopenharmony_ci		break;
26128c2ecf20Sopenharmony_ci
26138c2ecf20Sopenharmony_ci	case 38:	/* stb */
26148c2ecf20Sopenharmony_ci	case 39:	/* stbu */
26158c2ecf20Sopenharmony_ci		op->type = MKOP(STORE, u, 1);
26168c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26178c2ecf20Sopenharmony_ci		break;
26188c2ecf20Sopenharmony_ci
26198c2ecf20Sopenharmony_ci	case 40:	/* lhz */
26208c2ecf20Sopenharmony_ci	case 41:	/* lhzu */
26218c2ecf20Sopenharmony_ci		op->type = MKOP(LOAD, u, 2);
26228c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26238c2ecf20Sopenharmony_ci		break;
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	case 42:	/* lha */
26268c2ecf20Sopenharmony_ci	case 43:	/* lhau */
26278c2ecf20Sopenharmony_ci		op->type = MKOP(LOAD, SIGNEXT | u, 2);
26288c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26298c2ecf20Sopenharmony_ci		break;
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	case 44:	/* sth */
26328c2ecf20Sopenharmony_ci	case 45:	/* sthu */
26338c2ecf20Sopenharmony_ci		op->type = MKOP(STORE, u, 2);
26348c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26358c2ecf20Sopenharmony_ci		break;
26368c2ecf20Sopenharmony_ci
26378c2ecf20Sopenharmony_ci	case 46:	/* lmw */
26388c2ecf20Sopenharmony_ci		if (ra >= rd)
26398c2ecf20Sopenharmony_ci			break;		/* invalid form, ra in range to load */
26408c2ecf20Sopenharmony_ci		op->type = MKOP(LOAD_MULTI, 0, 4 * (32 - rd));
26418c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26428c2ecf20Sopenharmony_ci		break;
26438c2ecf20Sopenharmony_ci
26448c2ecf20Sopenharmony_ci	case 47:	/* stmw */
26458c2ecf20Sopenharmony_ci		op->type = MKOP(STORE_MULTI, 0, 4 * (32 - rd));
26468c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26478c2ecf20Sopenharmony_ci		break;
26488c2ecf20Sopenharmony_ci
26498c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_FPU
26508c2ecf20Sopenharmony_ci	case 48:	/* lfs */
26518c2ecf20Sopenharmony_ci	case 49:	/* lfsu */
26528c2ecf20Sopenharmony_ci		op->type = MKOP(LOAD_FP, u | FPCONV, 4);
26538c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26548c2ecf20Sopenharmony_ci		break;
26558c2ecf20Sopenharmony_ci
26568c2ecf20Sopenharmony_ci	case 50:	/* lfd */
26578c2ecf20Sopenharmony_ci	case 51:	/* lfdu */
26588c2ecf20Sopenharmony_ci		op->type = MKOP(LOAD_FP, u, 8);
26598c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26608c2ecf20Sopenharmony_ci		break;
26618c2ecf20Sopenharmony_ci
26628c2ecf20Sopenharmony_ci	case 52:	/* stfs */
26638c2ecf20Sopenharmony_ci	case 53:	/* stfsu */
26648c2ecf20Sopenharmony_ci		op->type = MKOP(STORE_FP, u | FPCONV, 4);
26658c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26668c2ecf20Sopenharmony_ci		break;
26678c2ecf20Sopenharmony_ci
26688c2ecf20Sopenharmony_ci	case 54:	/* stfd */
26698c2ecf20Sopenharmony_ci	case 55:	/* stfdu */
26708c2ecf20Sopenharmony_ci		op->type = MKOP(STORE_FP, u, 8);
26718c2ecf20Sopenharmony_ci		op->ea = dform_ea(word, regs);
26728c2ecf20Sopenharmony_ci		break;
26738c2ecf20Sopenharmony_ci#endif
26748c2ecf20Sopenharmony_ci
26758c2ecf20Sopenharmony_ci#ifdef __powerpc64__
26768c2ecf20Sopenharmony_ci	case 56:	/* lq */
26778c2ecf20Sopenharmony_ci		if (!((rd & 1) || (rd == ra)))
26788c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, 0, 16);
26798c2ecf20Sopenharmony_ci		op->ea = dqform_ea(word, regs);
26808c2ecf20Sopenharmony_ci		break;
26818c2ecf20Sopenharmony_ci#endif
26828c2ecf20Sopenharmony_ci
26838c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX
26848c2ecf20Sopenharmony_ci	case 57:	/* lfdp, lxsd, lxssp */
26858c2ecf20Sopenharmony_ci		op->ea = dsform_ea(word, regs);
26868c2ecf20Sopenharmony_ci		switch (word & 3) {
26878c2ecf20Sopenharmony_ci		case 0:		/* lfdp */
26888c2ecf20Sopenharmony_ci			if (rd & 1)
26898c2ecf20Sopenharmony_ci				break;		/* reg must be even */
26908c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_FP, 0, 16);
26918c2ecf20Sopenharmony_ci			break;
26928c2ecf20Sopenharmony_ci		case 2:		/* lxsd */
26938c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
26948c2ecf20Sopenharmony_ci				goto unknown_opcode;
26958c2ecf20Sopenharmony_ci			op->reg = rd + 32;
26968c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 8);
26978c2ecf20Sopenharmony_ci			op->element_size = 8;
26988c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
26998c2ecf20Sopenharmony_ci			break;
27008c2ecf20Sopenharmony_ci		case 3:		/* lxssp */
27018c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
27028c2ecf20Sopenharmony_ci				goto unknown_opcode;
27038c2ecf20Sopenharmony_ci			op->reg = rd + 32;
27048c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 4);
27058c2ecf20Sopenharmony_ci			op->element_size = 8;
27068c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_FPCONV | VSX_CHECK_VEC;
27078c2ecf20Sopenharmony_ci			break;
27088c2ecf20Sopenharmony_ci		}
27098c2ecf20Sopenharmony_ci		break;
27108c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_ci#ifdef __powerpc64__
27138c2ecf20Sopenharmony_ci	case 58:	/* ld[u], lwa */
27148c2ecf20Sopenharmony_ci		op->ea = dsform_ea(word, regs);
27158c2ecf20Sopenharmony_ci		switch (word & 3) {
27168c2ecf20Sopenharmony_ci		case 0:		/* ld */
27178c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, 0, 8);
27188c2ecf20Sopenharmony_ci			break;
27198c2ecf20Sopenharmony_ci		case 1:		/* ldu */
27208c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, UPDATE, 8);
27218c2ecf20Sopenharmony_ci			break;
27228c2ecf20Sopenharmony_ci		case 2:		/* lwa */
27238c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD, SIGNEXT, 4);
27248c2ecf20Sopenharmony_ci			break;
27258c2ecf20Sopenharmony_ci		}
27268c2ecf20Sopenharmony_ci		break;
27278c2ecf20Sopenharmony_ci#endif
27288c2ecf20Sopenharmony_ci
27298c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX
27308c2ecf20Sopenharmony_ci	case 61:	/* stfdp, lxv, stxsd, stxssp, stxv */
27318c2ecf20Sopenharmony_ci		switch (word & 7) {
27328c2ecf20Sopenharmony_ci		case 0:		/* stfdp with LSB of DS field = 0 */
27338c2ecf20Sopenharmony_ci		case 4:		/* stfdp with LSB of DS field = 1 */
27348c2ecf20Sopenharmony_ci			op->ea = dsform_ea(word, regs);
27358c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_FP, 0, 16);
27368c2ecf20Sopenharmony_ci			break;
27378c2ecf20Sopenharmony_ci
27388c2ecf20Sopenharmony_ci		case 1:		/* lxv */
27398c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
27408c2ecf20Sopenharmony_ci				goto unknown_opcode;
27418c2ecf20Sopenharmony_ci			op->ea = dqform_ea(word, regs);
27428c2ecf20Sopenharmony_ci			if (word & 8)
27438c2ecf20Sopenharmony_ci				op->reg = rd + 32;
27448c2ecf20Sopenharmony_ci			op->type = MKOP(LOAD_VSX, 0, 16);
27458c2ecf20Sopenharmony_ci			op->element_size = 16;
27468c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
27478c2ecf20Sopenharmony_ci			break;
27488c2ecf20Sopenharmony_ci
27498c2ecf20Sopenharmony_ci		case 2:		/* stxsd with LSB of DS field = 0 */
27508c2ecf20Sopenharmony_ci		case 6:		/* stxsd with LSB of DS field = 1 */
27518c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
27528c2ecf20Sopenharmony_ci				goto unknown_opcode;
27538c2ecf20Sopenharmony_ci			op->ea = dsform_ea(word, regs);
27548c2ecf20Sopenharmony_ci			op->reg = rd + 32;
27558c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 8);
27568c2ecf20Sopenharmony_ci			op->element_size = 8;
27578c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
27588c2ecf20Sopenharmony_ci			break;
27598c2ecf20Sopenharmony_ci
27608c2ecf20Sopenharmony_ci		case 3:		/* stxssp with LSB of DS field = 0 */
27618c2ecf20Sopenharmony_ci		case 7:		/* stxssp with LSB of DS field = 1 */
27628c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
27638c2ecf20Sopenharmony_ci				goto unknown_opcode;
27648c2ecf20Sopenharmony_ci			op->ea = dsform_ea(word, regs);
27658c2ecf20Sopenharmony_ci			op->reg = rd + 32;
27668c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 4);
27678c2ecf20Sopenharmony_ci			op->element_size = 8;
27688c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_FPCONV | VSX_CHECK_VEC;
27698c2ecf20Sopenharmony_ci			break;
27708c2ecf20Sopenharmony_ci
27718c2ecf20Sopenharmony_ci		case 5:		/* stxv */
27728c2ecf20Sopenharmony_ci			if (!cpu_has_feature(CPU_FTR_ARCH_300))
27738c2ecf20Sopenharmony_ci				goto unknown_opcode;
27748c2ecf20Sopenharmony_ci			op->ea = dqform_ea(word, regs);
27758c2ecf20Sopenharmony_ci			if (word & 8)
27768c2ecf20Sopenharmony_ci				op->reg = rd + 32;
27778c2ecf20Sopenharmony_ci			op->type = MKOP(STORE_VSX, 0, 16);
27788c2ecf20Sopenharmony_ci			op->element_size = 16;
27798c2ecf20Sopenharmony_ci			op->vsx_flags = VSX_CHECK_VEC;
27808c2ecf20Sopenharmony_ci			break;
27818c2ecf20Sopenharmony_ci		}
27828c2ecf20Sopenharmony_ci		break;
27838c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */
27848c2ecf20Sopenharmony_ci
27858c2ecf20Sopenharmony_ci#ifdef __powerpc64__
27868c2ecf20Sopenharmony_ci	case 62:	/* std[u] */
27878c2ecf20Sopenharmony_ci		op->ea = dsform_ea(word, regs);
27888c2ecf20Sopenharmony_ci		switch (word & 3) {
27898c2ecf20Sopenharmony_ci		case 0:		/* std */
27908c2ecf20Sopenharmony_ci			op->type = MKOP(STORE, 0, 8);
27918c2ecf20Sopenharmony_ci			break;
27928c2ecf20Sopenharmony_ci		case 1:		/* stdu */
27938c2ecf20Sopenharmony_ci			op->type = MKOP(STORE, UPDATE, 8);
27948c2ecf20Sopenharmony_ci			break;
27958c2ecf20Sopenharmony_ci		case 2:		/* stq */
27968c2ecf20Sopenharmony_ci			if (!(rd & 1))
27978c2ecf20Sopenharmony_ci				op->type = MKOP(STORE, 0, 16);
27988c2ecf20Sopenharmony_ci			break;
27998c2ecf20Sopenharmony_ci		}
28008c2ecf20Sopenharmony_ci		break;
28018c2ecf20Sopenharmony_ci	case 1: /* Prefixed instructions */
28028c2ecf20Sopenharmony_ci		if (!cpu_has_feature(CPU_FTR_ARCH_31))
28038c2ecf20Sopenharmony_ci			goto unknown_opcode;
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci		prefix_r = GET_PREFIX_R(word);
28068c2ecf20Sopenharmony_ci		ra = GET_PREFIX_RA(suffix);
28078c2ecf20Sopenharmony_ci		op->update_reg = ra;
28088c2ecf20Sopenharmony_ci		rd = (suffix >> 21) & 0x1f;
28098c2ecf20Sopenharmony_ci		op->reg = rd;
28108c2ecf20Sopenharmony_ci		op->val = regs->gpr[rd];
28118c2ecf20Sopenharmony_ci
28128c2ecf20Sopenharmony_ci		suffixopcode = get_op(suffix);
28138c2ecf20Sopenharmony_ci		prefixtype = (word >> 24) & 0x3;
28148c2ecf20Sopenharmony_ci		switch (prefixtype) {
28158c2ecf20Sopenharmony_ci		case 0: /* Type 00  Eight-Byte Load/Store */
28168c2ecf20Sopenharmony_ci			if (prefix_r && ra)
28178c2ecf20Sopenharmony_ci				break;
28188c2ecf20Sopenharmony_ci			op->ea = mlsd_8lsd_ea(word, suffix, regs);
28198c2ecf20Sopenharmony_ci			switch (suffixopcode) {
28208c2ecf20Sopenharmony_ci			case 41:	/* plwa */
28218c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD, PREFIXED | SIGNEXT, 4);
28228c2ecf20Sopenharmony_ci				break;
28238c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX
28248c2ecf20Sopenharmony_ci			case 42:        /* plxsd */
28258c2ecf20Sopenharmony_ci				op->reg = rd + 32;
28268c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD_VSX, PREFIXED, 8);
28278c2ecf20Sopenharmony_ci				op->element_size = 8;
28288c2ecf20Sopenharmony_ci				op->vsx_flags = VSX_CHECK_VEC;
28298c2ecf20Sopenharmony_ci				break;
28308c2ecf20Sopenharmony_ci			case 43:	/* plxssp */
28318c2ecf20Sopenharmony_ci				op->reg = rd + 32;
28328c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD_VSX, PREFIXED, 4);
28338c2ecf20Sopenharmony_ci				op->element_size = 8;
28348c2ecf20Sopenharmony_ci				op->vsx_flags = VSX_FPCONV | VSX_CHECK_VEC;
28358c2ecf20Sopenharmony_ci				break;
28368c2ecf20Sopenharmony_ci			case 46:	/* pstxsd */
28378c2ecf20Sopenharmony_ci				op->reg = rd + 32;
28388c2ecf20Sopenharmony_ci				op->type = MKOP(STORE_VSX, PREFIXED, 8);
28398c2ecf20Sopenharmony_ci				op->element_size = 8;
28408c2ecf20Sopenharmony_ci				op->vsx_flags = VSX_CHECK_VEC;
28418c2ecf20Sopenharmony_ci				break;
28428c2ecf20Sopenharmony_ci			case 47:	/* pstxssp */
28438c2ecf20Sopenharmony_ci				op->reg = rd + 32;
28448c2ecf20Sopenharmony_ci				op->type = MKOP(STORE_VSX, PREFIXED, 4);
28458c2ecf20Sopenharmony_ci				op->element_size = 8;
28468c2ecf20Sopenharmony_ci				op->vsx_flags = VSX_FPCONV | VSX_CHECK_VEC;
28478c2ecf20Sopenharmony_ci				break;
28488c2ecf20Sopenharmony_ci			case 51:	/* plxv1 */
28498c2ecf20Sopenharmony_ci				op->reg += 32;
28508c2ecf20Sopenharmony_ci				fallthrough;
28518c2ecf20Sopenharmony_ci			case 50:	/* plxv0 */
28528c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD_VSX, PREFIXED, 16);
28538c2ecf20Sopenharmony_ci				op->element_size = 16;
28548c2ecf20Sopenharmony_ci				op->vsx_flags = VSX_CHECK_VEC;
28558c2ecf20Sopenharmony_ci				break;
28568c2ecf20Sopenharmony_ci			case 55:	/* pstxv1 */
28578c2ecf20Sopenharmony_ci				op->reg = rd + 32;
28588c2ecf20Sopenharmony_ci				fallthrough;
28598c2ecf20Sopenharmony_ci			case 54:	/* pstxv0 */
28608c2ecf20Sopenharmony_ci				op->type = MKOP(STORE_VSX, PREFIXED, 16);
28618c2ecf20Sopenharmony_ci				op->element_size = 16;
28628c2ecf20Sopenharmony_ci				op->vsx_flags = VSX_CHECK_VEC;
28638c2ecf20Sopenharmony_ci				break;
28648c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */
28658c2ecf20Sopenharmony_ci			case 56:        /* plq */
28668c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD, PREFIXED, 16);
28678c2ecf20Sopenharmony_ci				break;
28688c2ecf20Sopenharmony_ci			case 57:	/* pld */
28698c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD, PREFIXED, 8);
28708c2ecf20Sopenharmony_ci				break;
28718c2ecf20Sopenharmony_ci			case 60:        /* pstq */
28728c2ecf20Sopenharmony_ci				op->type = MKOP(STORE, PREFIXED, 16);
28738c2ecf20Sopenharmony_ci				break;
28748c2ecf20Sopenharmony_ci			case 61:	/* pstd */
28758c2ecf20Sopenharmony_ci				op->type = MKOP(STORE, PREFIXED, 8);
28768c2ecf20Sopenharmony_ci				break;
28778c2ecf20Sopenharmony_ci			}
28788c2ecf20Sopenharmony_ci			break;
28798c2ecf20Sopenharmony_ci		case 1: /* Type 01 Eight-Byte Register-to-Register */
28808c2ecf20Sopenharmony_ci			break;
28818c2ecf20Sopenharmony_ci		case 2: /* Type 10 Modified Load/Store */
28828c2ecf20Sopenharmony_ci			if (prefix_r && ra)
28838c2ecf20Sopenharmony_ci				break;
28848c2ecf20Sopenharmony_ci			op->ea = mlsd_8lsd_ea(word, suffix, regs);
28858c2ecf20Sopenharmony_ci			switch (suffixopcode) {
28868c2ecf20Sopenharmony_ci			case 32:	/* plwz */
28878c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD, PREFIXED, 4);
28888c2ecf20Sopenharmony_ci				break;
28898c2ecf20Sopenharmony_ci			case 34:	/* plbz */
28908c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD, PREFIXED, 1);
28918c2ecf20Sopenharmony_ci				break;
28928c2ecf20Sopenharmony_ci			case 36:	/* pstw */
28938c2ecf20Sopenharmony_ci				op->type = MKOP(STORE, PREFIXED, 4);
28948c2ecf20Sopenharmony_ci				break;
28958c2ecf20Sopenharmony_ci			case 38:	/* pstb */
28968c2ecf20Sopenharmony_ci				op->type = MKOP(STORE, PREFIXED, 1);
28978c2ecf20Sopenharmony_ci				break;
28988c2ecf20Sopenharmony_ci			case 40:	/* plhz */
28998c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD, PREFIXED, 2);
29008c2ecf20Sopenharmony_ci				break;
29018c2ecf20Sopenharmony_ci			case 42:	/* plha */
29028c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD, PREFIXED | SIGNEXT, 2);
29038c2ecf20Sopenharmony_ci				break;
29048c2ecf20Sopenharmony_ci			case 44:	/* psth */
29058c2ecf20Sopenharmony_ci				op->type = MKOP(STORE, PREFIXED, 2);
29068c2ecf20Sopenharmony_ci				break;
29078c2ecf20Sopenharmony_ci			case 48:        /* plfs */
29088c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD_FP, PREFIXED | FPCONV, 4);
29098c2ecf20Sopenharmony_ci				break;
29108c2ecf20Sopenharmony_ci			case 50:        /* plfd */
29118c2ecf20Sopenharmony_ci				op->type = MKOP(LOAD_FP, PREFIXED, 8);
29128c2ecf20Sopenharmony_ci				break;
29138c2ecf20Sopenharmony_ci			case 52:        /* pstfs */
29148c2ecf20Sopenharmony_ci				op->type = MKOP(STORE_FP, PREFIXED | FPCONV, 4);
29158c2ecf20Sopenharmony_ci				break;
29168c2ecf20Sopenharmony_ci			case 54:        /* pstfd */
29178c2ecf20Sopenharmony_ci				op->type = MKOP(STORE_FP, PREFIXED, 8);
29188c2ecf20Sopenharmony_ci				break;
29198c2ecf20Sopenharmony_ci			}
29208c2ecf20Sopenharmony_ci			break;
29218c2ecf20Sopenharmony_ci		case 3: /* Type 11 Modified Register-to-Register */
29228c2ecf20Sopenharmony_ci			break;
29238c2ecf20Sopenharmony_ci		}
29248c2ecf20Sopenharmony_ci#endif /* __powerpc64__ */
29258c2ecf20Sopenharmony_ci
29268c2ecf20Sopenharmony_ci	}
29278c2ecf20Sopenharmony_ci
29288c2ecf20Sopenharmony_ci	if (OP_IS_LOAD_STORE(op->type) && (op->type & UPDATE)) {
29298c2ecf20Sopenharmony_ci		switch (GETTYPE(op->type)) {
29308c2ecf20Sopenharmony_ci		case LOAD:
29318c2ecf20Sopenharmony_ci			if (ra == rd)
29328c2ecf20Sopenharmony_ci				goto unknown_opcode;
29338c2ecf20Sopenharmony_ci			fallthrough;
29348c2ecf20Sopenharmony_ci		case STORE:
29358c2ecf20Sopenharmony_ci		case LOAD_FP:
29368c2ecf20Sopenharmony_ci		case STORE_FP:
29378c2ecf20Sopenharmony_ci			if (ra == 0)
29388c2ecf20Sopenharmony_ci				goto unknown_opcode;
29398c2ecf20Sopenharmony_ci		}
29408c2ecf20Sopenharmony_ci	}
29418c2ecf20Sopenharmony_ci
29428c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX
29438c2ecf20Sopenharmony_ci	if ((GETTYPE(op->type) == LOAD_VSX ||
29448c2ecf20Sopenharmony_ci	     GETTYPE(op->type) == STORE_VSX) &&
29458c2ecf20Sopenharmony_ci	    !cpu_has_feature(CPU_FTR_VSX)) {
29468c2ecf20Sopenharmony_ci		return -1;
29478c2ecf20Sopenharmony_ci	}
29488c2ecf20Sopenharmony_ci#endif /* CONFIG_VSX */
29498c2ecf20Sopenharmony_ci
29508c2ecf20Sopenharmony_ci	return 0;
29518c2ecf20Sopenharmony_ci
29528c2ecf20Sopenharmony_ci unknown_opcode:
29538c2ecf20Sopenharmony_ci	op->type = UNKNOWN;
29548c2ecf20Sopenharmony_ci	return 0;
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_ci logical_done:
29578c2ecf20Sopenharmony_ci	if (word & 1)
29588c2ecf20Sopenharmony_ci		set_cr0(regs, op);
29598c2ecf20Sopenharmony_ci logical_done_nocc:
29608c2ecf20Sopenharmony_ci	op->reg = ra;
29618c2ecf20Sopenharmony_ci	op->type |= SETREG;
29628c2ecf20Sopenharmony_ci	return 1;
29638c2ecf20Sopenharmony_ci
29648c2ecf20Sopenharmony_ci arith_done:
29658c2ecf20Sopenharmony_ci	if (word & 1)
29668c2ecf20Sopenharmony_ci		set_cr0(regs, op);
29678c2ecf20Sopenharmony_ci compute_done:
29688c2ecf20Sopenharmony_ci	op->reg = rd;
29698c2ecf20Sopenharmony_ci	op->type |= SETREG;
29708c2ecf20Sopenharmony_ci	return 1;
29718c2ecf20Sopenharmony_ci
29728c2ecf20Sopenharmony_ci priv:
29738c2ecf20Sopenharmony_ci	op->type = INTERRUPT | 0x700;
29748c2ecf20Sopenharmony_ci	op->val = SRR1_PROGPRIV;
29758c2ecf20Sopenharmony_ci	return 0;
29768c2ecf20Sopenharmony_ci
29778c2ecf20Sopenharmony_ci trap:
29788c2ecf20Sopenharmony_ci	op->type = INTERRUPT | 0x700;
29798c2ecf20Sopenharmony_ci	op->val = SRR1_PROGTRAP;
29808c2ecf20Sopenharmony_ci	return 0;
29818c2ecf20Sopenharmony_ci}
29828c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(analyse_instr);
29838c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(analyse_instr);
29848c2ecf20Sopenharmony_ci
29858c2ecf20Sopenharmony_ci/*
29868c2ecf20Sopenharmony_ci * For PPC32 we always use stwu with r1 to change the stack pointer.
29878c2ecf20Sopenharmony_ci * So this emulated store may corrupt the exception frame, now we
29888c2ecf20Sopenharmony_ci * have to provide the exception frame trampoline, which is pushed
29898c2ecf20Sopenharmony_ci * below the kprobed function stack. So we only update gpr[1] but
29908c2ecf20Sopenharmony_ci * don't emulate the real store operation. We will do real store
29918c2ecf20Sopenharmony_ci * operation safely in exception return code by checking this flag.
29928c2ecf20Sopenharmony_ci */
29938c2ecf20Sopenharmony_cistatic nokprobe_inline int handle_stack_update(unsigned long ea, struct pt_regs *regs)
29948c2ecf20Sopenharmony_ci{
29958c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC32
29968c2ecf20Sopenharmony_ci	/*
29978c2ecf20Sopenharmony_ci	 * Check if we will touch kernel stack overflow
29988c2ecf20Sopenharmony_ci	 */
29998c2ecf20Sopenharmony_ci	if (ea - STACK_INT_FRAME_SIZE <= current->thread.ksp_limit) {
30008c2ecf20Sopenharmony_ci		printk(KERN_CRIT "Can't kprobe this since kernel stack would overflow.\n");
30018c2ecf20Sopenharmony_ci		return -EINVAL;
30028c2ecf20Sopenharmony_ci	}
30038c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC32 */
30048c2ecf20Sopenharmony_ci	/*
30058c2ecf20Sopenharmony_ci	 * Check if we already set since that means we'll
30068c2ecf20Sopenharmony_ci	 * lose the previous value.
30078c2ecf20Sopenharmony_ci	 */
30088c2ecf20Sopenharmony_ci	WARN_ON(test_thread_flag(TIF_EMULATE_STACK_STORE));
30098c2ecf20Sopenharmony_ci	set_thread_flag(TIF_EMULATE_STACK_STORE);
30108c2ecf20Sopenharmony_ci	return 0;
30118c2ecf20Sopenharmony_ci}
30128c2ecf20Sopenharmony_ci
30138c2ecf20Sopenharmony_cistatic nokprobe_inline void do_signext(unsigned long *valp, int size)
30148c2ecf20Sopenharmony_ci{
30158c2ecf20Sopenharmony_ci	switch (size) {
30168c2ecf20Sopenharmony_ci	case 2:
30178c2ecf20Sopenharmony_ci		*valp = (signed short) *valp;
30188c2ecf20Sopenharmony_ci		break;
30198c2ecf20Sopenharmony_ci	case 4:
30208c2ecf20Sopenharmony_ci		*valp = (signed int) *valp;
30218c2ecf20Sopenharmony_ci		break;
30228c2ecf20Sopenharmony_ci	}
30238c2ecf20Sopenharmony_ci}
30248c2ecf20Sopenharmony_ci
30258c2ecf20Sopenharmony_cistatic nokprobe_inline void do_byterev(unsigned long *valp, int size)
30268c2ecf20Sopenharmony_ci{
30278c2ecf20Sopenharmony_ci	switch (size) {
30288c2ecf20Sopenharmony_ci	case 2:
30298c2ecf20Sopenharmony_ci		*valp = byterev_2(*valp);
30308c2ecf20Sopenharmony_ci		break;
30318c2ecf20Sopenharmony_ci	case 4:
30328c2ecf20Sopenharmony_ci		*valp = byterev_4(*valp);
30338c2ecf20Sopenharmony_ci		break;
30348c2ecf20Sopenharmony_ci#ifdef __powerpc64__
30358c2ecf20Sopenharmony_ci	case 8:
30368c2ecf20Sopenharmony_ci		*valp = byterev_8(*valp);
30378c2ecf20Sopenharmony_ci		break;
30388c2ecf20Sopenharmony_ci#endif
30398c2ecf20Sopenharmony_ci	}
30408c2ecf20Sopenharmony_ci}
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_ci/*
30438c2ecf20Sopenharmony_ci * Emulate an instruction that can be executed just by updating
30448c2ecf20Sopenharmony_ci * fields in *regs.
30458c2ecf20Sopenharmony_ci */
30468c2ecf20Sopenharmony_civoid emulate_update_regs(struct pt_regs *regs, struct instruction_op *op)
30478c2ecf20Sopenharmony_ci{
30488c2ecf20Sopenharmony_ci	unsigned long next_pc;
30498c2ecf20Sopenharmony_ci
30508c2ecf20Sopenharmony_ci	next_pc = truncate_if_32bit(regs->msr, regs->nip + GETLENGTH(op->type));
30518c2ecf20Sopenharmony_ci	switch (GETTYPE(op->type)) {
30528c2ecf20Sopenharmony_ci	case COMPUTE:
30538c2ecf20Sopenharmony_ci		if (op->type & SETREG)
30548c2ecf20Sopenharmony_ci			regs->gpr[op->reg] = op->val;
30558c2ecf20Sopenharmony_ci		if (op->type & SETCC)
30568c2ecf20Sopenharmony_ci			regs->ccr = op->ccval;
30578c2ecf20Sopenharmony_ci		if (op->type & SETXER)
30588c2ecf20Sopenharmony_ci			regs->xer = op->xerval;
30598c2ecf20Sopenharmony_ci		break;
30608c2ecf20Sopenharmony_ci
30618c2ecf20Sopenharmony_ci	case BRANCH:
30628c2ecf20Sopenharmony_ci		if (op->type & SETLK)
30638c2ecf20Sopenharmony_ci			regs->link = next_pc;
30648c2ecf20Sopenharmony_ci		if (op->type & BRTAKEN)
30658c2ecf20Sopenharmony_ci			next_pc = op->val;
30668c2ecf20Sopenharmony_ci		if (op->type & DECCTR)
30678c2ecf20Sopenharmony_ci			--regs->ctr;
30688c2ecf20Sopenharmony_ci		break;
30698c2ecf20Sopenharmony_ci
30708c2ecf20Sopenharmony_ci	case BARRIER:
30718c2ecf20Sopenharmony_ci		switch (op->type & BARRIER_MASK) {
30728c2ecf20Sopenharmony_ci		case BARRIER_SYNC:
30738c2ecf20Sopenharmony_ci			mb();
30748c2ecf20Sopenharmony_ci			break;
30758c2ecf20Sopenharmony_ci		case BARRIER_ISYNC:
30768c2ecf20Sopenharmony_ci			isync();
30778c2ecf20Sopenharmony_ci			break;
30788c2ecf20Sopenharmony_ci		case BARRIER_EIEIO:
30798c2ecf20Sopenharmony_ci			eieio();
30808c2ecf20Sopenharmony_ci			break;
30818c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
30828c2ecf20Sopenharmony_ci		case BARRIER_LWSYNC:
30838c2ecf20Sopenharmony_ci			asm volatile("lwsync" : : : "memory");
30848c2ecf20Sopenharmony_ci			break;
30858c2ecf20Sopenharmony_ci		case BARRIER_PTESYNC:
30868c2ecf20Sopenharmony_ci			asm volatile("ptesync" : : : "memory");
30878c2ecf20Sopenharmony_ci			break;
30888c2ecf20Sopenharmony_ci#endif
30898c2ecf20Sopenharmony_ci		}
30908c2ecf20Sopenharmony_ci		break;
30918c2ecf20Sopenharmony_ci
30928c2ecf20Sopenharmony_ci	case MFSPR:
30938c2ecf20Sopenharmony_ci		switch (op->spr) {
30948c2ecf20Sopenharmony_ci		case SPRN_XER:
30958c2ecf20Sopenharmony_ci			regs->gpr[op->reg] = regs->xer & 0xffffffffUL;
30968c2ecf20Sopenharmony_ci			break;
30978c2ecf20Sopenharmony_ci		case SPRN_LR:
30988c2ecf20Sopenharmony_ci			regs->gpr[op->reg] = regs->link;
30998c2ecf20Sopenharmony_ci			break;
31008c2ecf20Sopenharmony_ci		case SPRN_CTR:
31018c2ecf20Sopenharmony_ci			regs->gpr[op->reg] = regs->ctr;
31028c2ecf20Sopenharmony_ci			break;
31038c2ecf20Sopenharmony_ci		default:
31048c2ecf20Sopenharmony_ci			WARN_ON_ONCE(1);
31058c2ecf20Sopenharmony_ci		}
31068c2ecf20Sopenharmony_ci		break;
31078c2ecf20Sopenharmony_ci
31088c2ecf20Sopenharmony_ci	case MTSPR:
31098c2ecf20Sopenharmony_ci		switch (op->spr) {
31108c2ecf20Sopenharmony_ci		case SPRN_XER:
31118c2ecf20Sopenharmony_ci			regs->xer = op->val & 0xffffffffUL;
31128c2ecf20Sopenharmony_ci			break;
31138c2ecf20Sopenharmony_ci		case SPRN_LR:
31148c2ecf20Sopenharmony_ci			regs->link = op->val;
31158c2ecf20Sopenharmony_ci			break;
31168c2ecf20Sopenharmony_ci		case SPRN_CTR:
31178c2ecf20Sopenharmony_ci			regs->ctr = op->val;
31188c2ecf20Sopenharmony_ci			break;
31198c2ecf20Sopenharmony_ci		default:
31208c2ecf20Sopenharmony_ci			WARN_ON_ONCE(1);
31218c2ecf20Sopenharmony_ci		}
31228c2ecf20Sopenharmony_ci		break;
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci	default:
31258c2ecf20Sopenharmony_ci		WARN_ON_ONCE(1);
31268c2ecf20Sopenharmony_ci	}
31278c2ecf20Sopenharmony_ci	regs->nip = next_pc;
31288c2ecf20Sopenharmony_ci}
31298c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(emulate_update_regs);
31308c2ecf20Sopenharmony_ci
31318c2ecf20Sopenharmony_ci/*
31328c2ecf20Sopenharmony_ci * Emulate a previously-analysed load or store instruction.
31338c2ecf20Sopenharmony_ci * Return values are:
31348c2ecf20Sopenharmony_ci * 0 = instruction emulated successfully
31358c2ecf20Sopenharmony_ci * -EFAULT = address out of range or access faulted (regs->dar
31368c2ecf20Sopenharmony_ci *	     contains the faulting address)
31378c2ecf20Sopenharmony_ci * -EACCES = misaligned access, instruction requires alignment
31388c2ecf20Sopenharmony_ci * -EINVAL = unknown operation in *op
31398c2ecf20Sopenharmony_ci */
31408c2ecf20Sopenharmony_ciint emulate_loadstore(struct pt_regs *regs, struct instruction_op *op)
31418c2ecf20Sopenharmony_ci{
31428c2ecf20Sopenharmony_ci	int err, size, type;
31438c2ecf20Sopenharmony_ci	int i, rd, nb;
31448c2ecf20Sopenharmony_ci	unsigned int cr;
31458c2ecf20Sopenharmony_ci	unsigned long val;
31468c2ecf20Sopenharmony_ci	unsigned long ea;
31478c2ecf20Sopenharmony_ci	bool cross_endian;
31488c2ecf20Sopenharmony_ci
31498c2ecf20Sopenharmony_ci	err = 0;
31508c2ecf20Sopenharmony_ci	size = GETSIZE(op->type);
31518c2ecf20Sopenharmony_ci	type = GETTYPE(op->type);
31528c2ecf20Sopenharmony_ci	cross_endian = (regs->msr & MSR_LE) != (MSR_KERNEL & MSR_LE);
31538c2ecf20Sopenharmony_ci	ea = truncate_if_32bit(regs->msr, op->ea);
31548c2ecf20Sopenharmony_ci
31558c2ecf20Sopenharmony_ci	switch (type) {
31568c2ecf20Sopenharmony_ci	case LARX:
31578c2ecf20Sopenharmony_ci		if (ea & (size - 1))
31588c2ecf20Sopenharmony_ci			return -EACCES;		/* can't handle misaligned */
31598c2ecf20Sopenharmony_ci		if (!address_ok(regs, ea, size))
31608c2ecf20Sopenharmony_ci			return -EFAULT;
31618c2ecf20Sopenharmony_ci		err = 0;
31628c2ecf20Sopenharmony_ci		val = 0;
31638c2ecf20Sopenharmony_ci		switch (size) {
31648c2ecf20Sopenharmony_ci#ifdef __powerpc64__
31658c2ecf20Sopenharmony_ci		case 1:
31668c2ecf20Sopenharmony_ci			__get_user_asmx(val, ea, err, "lbarx");
31678c2ecf20Sopenharmony_ci			break;
31688c2ecf20Sopenharmony_ci		case 2:
31698c2ecf20Sopenharmony_ci			__get_user_asmx(val, ea, err, "lharx");
31708c2ecf20Sopenharmony_ci			break;
31718c2ecf20Sopenharmony_ci#endif
31728c2ecf20Sopenharmony_ci		case 4:
31738c2ecf20Sopenharmony_ci			__get_user_asmx(val, ea, err, "lwarx");
31748c2ecf20Sopenharmony_ci			break;
31758c2ecf20Sopenharmony_ci#ifdef __powerpc64__
31768c2ecf20Sopenharmony_ci		case 8:
31778c2ecf20Sopenharmony_ci			__get_user_asmx(val, ea, err, "ldarx");
31788c2ecf20Sopenharmony_ci			break;
31798c2ecf20Sopenharmony_ci		case 16:
31808c2ecf20Sopenharmony_ci			err = do_lqarx(ea, &regs->gpr[op->reg]);
31818c2ecf20Sopenharmony_ci			break;
31828c2ecf20Sopenharmony_ci#endif
31838c2ecf20Sopenharmony_ci		default:
31848c2ecf20Sopenharmony_ci			return -EINVAL;
31858c2ecf20Sopenharmony_ci		}
31868c2ecf20Sopenharmony_ci		if (err) {
31878c2ecf20Sopenharmony_ci			regs->dar = ea;
31888c2ecf20Sopenharmony_ci			break;
31898c2ecf20Sopenharmony_ci		}
31908c2ecf20Sopenharmony_ci		if (size < 16)
31918c2ecf20Sopenharmony_ci			regs->gpr[op->reg] = val;
31928c2ecf20Sopenharmony_ci		break;
31938c2ecf20Sopenharmony_ci
31948c2ecf20Sopenharmony_ci	case STCX:
31958c2ecf20Sopenharmony_ci		if (ea & (size - 1))
31968c2ecf20Sopenharmony_ci			return -EACCES;		/* can't handle misaligned */
31978c2ecf20Sopenharmony_ci		if (!address_ok(regs, ea, size))
31988c2ecf20Sopenharmony_ci			return -EFAULT;
31998c2ecf20Sopenharmony_ci		err = 0;
32008c2ecf20Sopenharmony_ci		switch (size) {
32018c2ecf20Sopenharmony_ci#ifdef __powerpc64__
32028c2ecf20Sopenharmony_ci		case 1:
32038c2ecf20Sopenharmony_ci			__put_user_asmx(op->val, ea, err, "stbcx.", cr);
32048c2ecf20Sopenharmony_ci			break;
32058c2ecf20Sopenharmony_ci		case 2:
32068c2ecf20Sopenharmony_ci			__put_user_asmx(op->val, ea, err, "sthcx.", cr);
32078c2ecf20Sopenharmony_ci			break;
32088c2ecf20Sopenharmony_ci#endif
32098c2ecf20Sopenharmony_ci		case 4:
32108c2ecf20Sopenharmony_ci			__put_user_asmx(op->val, ea, err, "stwcx.", cr);
32118c2ecf20Sopenharmony_ci			break;
32128c2ecf20Sopenharmony_ci#ifdef __powerpc64__
32138c2ecf20Sopenharmony_ci		case 8:
32148c2ecf20Sopenharmony_ci			__put_user_asmx(op->val, ea, err, "stdcx.", cr);
32158c2ecf20Sopenharmony_ci			break;
32168c2ecf20Sopenharmony_ci		case 16:
32178c2ecf20Sopenharmony_ci			err = do_stqcx(ea, regs->gpr[op->reg],
32188c2ecf20Sopenharmony_ci				       regs->gpr[op->reg + 1], &cr);
32198c2ecf20Sopenharmony_ci			break;
32208c2ecf20Sopenharmony_ci#endif
32218c2ecf20Sopenharmony_ci		default:
32228c2ecf20Sopenharmony_ci			return -EINVAL;
32238c2ecf20Sopenharmony_ci		}
32248c2ecf20Sopenharmony_ci		if (!err)
32258c2ecf20Sopenharmony_ci			regs->ccr = (regs->ccr & 0x0fffffff) |
32268c2ecf20Sopenharmony_ci				(cr & 0xe0000000) |
32278c2ecf20Sopenharmony_ci				((regs->xer >> 3) & 0x10000000);
32288c2ecf20Sopenharmony_ci		else
32298c2ecf20Sopenharmony_ci			regs->dar = ea;
32308c2ecf20Sopenharmony_ci		break;
32318c2ecf20Sopenharmony_ci
32328c2ecf20Sopenharmony_ci	case LOAD:
32338c2ecf20Sopenharmony_ci#ifdef __powerpc64__
32348c2ecf20Sopenharmony_ci		if (size == 16) {
32358c2ecf20Sopenharmony_ci			err = emulate_lq(regs, ea, op->reg, cross_endian);
32368c2ecf20Sopenharmony_ci			break;
32378c2ecf20Sopenharmony_ci		}
32388c2ecf20Sopenharmony_ci#endif
32398c2ecf20Sopenharmony_ci		err = read_mem(&regs->gpr[op->reg], ea, size, regs);
32408c2ecf20Sopenharmony_ci		if (!err) {
32418c2ecf20Sopenharmony_ci			if (op->type & SIGNEXT)
32428c2ecf20Sopenharmony_ci				do_signext(&regs->gpr[op->reg], size);
32438c2ecf20Sopenharmony_ci			if ((op->type & BYTEREV) == (cross_endian ? 0 : BYTEREV))
32448c2ecf20Sopenharmony_ci				do_byterev(&regs->gpr[op->reg], size);
32458c2ecf20Sopenharmony_ci		}
32468c2ecf20Sopenharmony_ci		break;
32478c2ecf20Sopenharmony_ci
32488c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_FPU
32498c2ecf20Sopenharmony_ci	case LOAD_FP:
32508c2ecf20Sopenharmony_ci		/*
32518c2ecf20Sopenharmony_ci		 * If the instruction is in userspace, we can emulate it even
32528c2ecf20Sopenharmony_ci		 * if the VMX state is not live, because we have the state
32538c2ecf20Sopenharmony_ci		 * stored in the thread_struct.  If the instruction is in
32548c2ecf20Sopenharmony_ci		 * the kernel, we must not touch the state in the thread_struct.
32558c2ecf20Sopenharmony_ci		 */
32568c2ecf20Sopenharmony_ci		if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_FP))
32578c2ecf20Sopenharmony_ci			return 0;
32588c2ecf20Sopenharmony_ci		err = do_fp_load(op, ea, regs, cross_endian);
32598c2ecf20Sopenharmony_ci		break;
32608c2ecf20Sopenharmony_ci#endif
32618c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC
32628c2ecf20Sopenharmony_ci	case LOAD_VMX:
32638c2ecf20Sopenharmony_ci		if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_VEC))
32648c2ecf20Sopenharmony_ci			return 0;
32658c2ecf20Sopenharmony_ci		err = do_vec_load(op->reg, ea, size, regs, cross_endian);
32668c2ecf20Sopenharmony_ci		break;
32678c2ecf20Sopenharmony_ci#endif
32688c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX
32698c2ecf20Sopenharmony_ci	case LOAD_VSX: {
32708c2ecf20Sopenharmony_ci		unsigned long msrbit = MSR_VSX;
32718c2ecf20Sopenharmony_ci
32728c2ecf20Sopenharmony_ci		/*
32738c2ecf20Sopenharmony_ci		 * Some VSX instructions check the MSR_VEC bit rather than MSR_VSX
32748c2ecf20Sopenharmony_ci		 * when the target of the instruction is a vector register.
32758c2ecf20Sopenharmony_ci		 */
32768c2ecf20Sopenharmony_ci		if (op->reg >= 32 && (op->vsx_flags & VSX_CHECK_VEC))
32778c2ecf20Sopenharmony_ci			msrbit = MSR_VEC;
32788c2ecf20Sopenharmony_ci		if (!(regs->msr & MSR_PR) && !(regs->msr & msrbit))
32798c2ecf20Sopenharmony_ci			return 0;
32808c2ecf20Sopenharmony_ci		err = do_vsx_load(op, ea, regs, cross_endian);
32818c2ecf20Sopenharmony_ci		break;
32828c2ecf20Sopenharmony_ci	}
32838c2ecf20Sopenharmony_ci#endif
32848c2ecf20Sopenharmony_ci	case LOAD_MULTI:
32858c2ecf20Sopenharmony_ci		if (!address_ok(regs, ea, size))
32868c2ecf20Sopenharmony_ci			return -EFAULT;
32878c2ecf20Sopenharmony_ci		rd = op->reg;
32888c2ecf20Sopenharmony_ci		for (i = 0; i < size; i += 4) {
32898c2ecf20Sopenharmony_ci			unsigned int v32 = 0;
32908c2ecf20Sopenharmony_ci
32918c2ecf20Sopenharmony_ci			nb = size - i;
32928c2ecf20Sopenharmony_ci			if (nb > 4)
32938c2ecf20Sopenharmony_ci				nb = 4;
32948c2ecf20Sopenharmony_ci			err = copy_mem_in((u8 *) &v32, ea, nb, regs);
32958c2ecf20Sopenharmony_ci			if (err)
32968c2ecf20Sopenharmony_ci				break;
32978c2ecf20Sopenharmony_ci			if (unlikely(cross_endian))
32988c2ecf20Sopenharmony_ci				v32 = byterev_4(v32);
32998c2ecf20Sopenharmony_ci			regs->gpr[rd] = v32;
33008c2ecf20Sopenharmony_ci			ea += 4;
33018c2ecf20Sopenharmony_ci			/* reg number wraps from 31 to 0 for lsw[ix] */
33028c2ecf20Sopenharmony_ci			rd = (rd + 1) & 0x1f;
33038c2ecf20Sopenharmony_ci		}
33048c2ecf20Sopenharmony_ci		break;
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	case STORE:
33078c2ecf20Sopenharmony_ci#ifdef __powerpc64__
33088c2ecf20Sopenharmony_ci		if (size == 16) {
33098c2ecf20Sopenharmony_ci			err = emulate_stq(regs, ea, op->reg, cross_endian);
33108c2ecf20Sopenharmony_ci			break;
33118c2ecf20Sopenharmony_ci		}
33128c2ecf20Sopenharmony_ci#endif
33138c2ecf20Sopenharmony_ci		if ((op->type & UPDATE) && size == sizeof(long) &&
33148c2ecf20Sopenharmony_ci		    op->reg == 1 && op->update_reg == 1 &&
33158c2ecf20Sopenharmony_ci		    !(regs->msr & MSR_PR) &&
33168c2ecf20Sopenharmony_ci		    ea >= regs->gpr[1] - STACK_INT_FRAME_SIZE) {
33178c2ecf20Sopenharmony_ci			err = handle_stack_update(ea, regs);
33188c2ecf20Sopenharmony_ci			break;
33198c2ecf20Sopenharmony_ci		}
33208c2ecf20Sopenharmony_ci		if (unlikely(cross_endian))
33218c2ecf20Sopenharmony_ci			do_byterev(&op->val, size);
33228c2ecf20Sopenharmony_ci		err = write_mem(op->val, ea, size, regs);
33238c2ecf20Sopenharmony_ci		break;
33248c2ecf20Sopenharmony_ci
33258c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_FPU
33268c2ecf20Sopenharmony_ci	case STORE_FP:
33278c2ecf20Sopenharmony_ci		if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_FP))
33288c2ecf20Sopenharmony_ci			return 0;
33298c2ecf20Sopenharmony_ci		err = do_fp_store(op, ea, regs, cross_endian);
33308c2ecf20Sopenharmony_ci		break;
33318c2ecf20Sopenharmony_ci#endif
33328c2ecf20Sopenharmony_ci#ifdef CONFIG_ALTIVEC
33338c2ecf20Sopenharmony_ci	case STORE_VMX:
33348c2ecf20Sopenharmony_ci		if (!(regs->msr & MSR_PR) && !(regs->msr & MSR_VEC))
33358c2ecf20Sopenharmony_ci			return 0;
33368c2ecf20Sopenharmony_ci		err = do_vec_store(op->reg, ea, size, regs, cross_endian);
33378c2ecf20Sopenharmony_ci		break;
33388c2ecf20Sopenharmony_ci#endif
33398c2ecf20Sopenharmony_ci#ifdef CONFIG_VSX
33408c2ecf20Sopenharmony_ci	case STORE_VSX: {
33418c2ecf20Sopenharmony_ci		unsigned long msrbit = MSR_VSX;
33428c2ecf20Sopenharmony_ci
33438c2ecf20Sopenharmony_ci		/*
33448c2ecf20Sopenharmony_ci		 * Some VSX instructions check the MSR_VEC bit rather than MSR_VSX
33458c2ecf20Sopenharmony_ci		 * when the target of the instruction is a vector register.
33468c2ecf20Sopenharmony_ci		 */
33478c2ecf20Sopenharmony_ci		if (op->reg >= 32 && (op->vsx_flags & VSX_CHECK_VEC))
33488c2ecf20Sopenharmony_ci			msrbit = MSR_VEC;
33498c2ecf20Sopenharmony_ci		if (!(regs->msr & MSR_PR) && !(regs->msr & msrbit))
33508c2ecf20Sopenharmony_ci			return 0;
33518c2ecf20Sopenharmony_ci		err = do_vsx_store(op, ea, regs, cross_endian);
33528c2ecf20Sopenharmony_ci		break;
33538c2ecf20Sopenharmony_ci	}
33548c2ecf20Sopenharmony_ci#endif
33558c2ecf20Sopenharmony_ci	case STORE_MULTI:
33568c2ecf20Sopenharmony_ci		if (!address_ok(regs, ea, size))
33578c2ecf20Sopenharmony_ci			return -EFAULT;
33588c2ecf20Sopenharmony_ci		rd = op->reg;
33598c2ecf20Sopenharmony_ci		for (i = 0; i < size; i += 4) {
33608c2ecf20Sopenharmony_ci			unsigned int v32 = regs->gpr[rd];
33618c2ecf20Sopenharmony_ci
33628c2ecf20Sopenharmony_ci			nb = size - i;
33638c2ecf20Sopenharmony_ci			if (nb > 4)
33648c2ecf20Sopenharmony_ci				nb = 4;
33658c2ecf20Sopenharmony_ci			if (unlikely(cross_endian))
33668c2ecf20Sopenharmony_ci				v32 = byterev_4(v32);
33678c2ecf20Sopenharmony_ci			err = copy_mem_out((u8 *) &v32, ea, nb, regs);
33688c2ecf20Sopenharmony_ci			if (err)
33698c2ecf20Sopenharmony_ci				break;
33708c2ecf20Sopenharmony_ci			ea += 4;
33718c2ecf20Sopenharmony_ci			/* reg number wraps from 31 to 0 for stsw[ix] */
33728c2ecf20Sopenharmony_ci			rd = (rd + 1) & 0x1f;
33738c2ecf20Sopenharmony_ci		}
33748c2ecf20Sopenharmony_ci		break;
33758c2ecf20Sopenharmony_ci
33768c2ecf20Sopenharmony_ci	default:
33778c2ecf20Sopenharmony_ci		return -EINVAL;
33788c2ecf20Sopenharmony_ci	}
33798c2ecf20Sopenharmony_ci
33808c2ecf20Sopenharmony_ci	if (err)
33818c2ecf20Sopenharmony_ci		return err;
33828c2ecf20Sopenharmony_ci
33838c2ecf20Sopenharmony_ci	if (op->type & UPDATE)
33848c2ecf20Sopenharmony_ci		regs->gpr[op->update_reg] = op->ea;
33858c2ecf20Sopenharmony_ci
33868c2ecf20Sopenharmony_ci	return 0;
33878c2ecf20Sopenharmony_ci}
33888c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(emulate_loadstore);
33898c2ecf20Sopenharmony_ci
33908c2ecf20Sopenharmony_ci/*
33918c2ecf20Sopenharmony_ci * Emulate instructions that cause a transfer of control,
33928c2ecf20Sopenharmony_ci * loads and stores, and a few other instructions.
33938c2ecf20Sopenharmony_ci * Returns 1 if the step was emulated, 0 if not,
33948c2ecf20Sopenharmony_ci * or -1 if the instruction is one that should not be stepped,
33958c2ecf20Sopenharmony_ci * such as an rfid, or a mtmsrd that would clear MSR_RI.
33968c2ecf20Sopenharmony_ci */
33978c2ecf20Sopenharmony_ciint emulate_step(struct pt_regs *regs, struct ppc_inst instr)
33988c2ecf20Sopenharmony_ci{
33998c2ecf20Sopenharmony_ci	struct instruction_op op;
34008c2ecf20Sopenharmony_ci	int r, err, type;
34018c2ecf20Sopenharmony_ci	unsigned long val;
34028c2ecf20Sopenharmony_ci	unsigned long ea;
34038c2ecf20Sopenharmony_ci
34048c2ecf20Sopenharmony_ci	r = analyse_instr(&op, regs, instr);
34058c2ecf20Sopenharmony_ci	if (r < 0)
34068c2ecf20Sopenharmony_ci		return r;
34078c2ecf20Sopenharmony_ci	if (r > 0) {
34088c2ecf20Sopenharmony_ci		emulate_update_regs(regs, &op);
34098c2ecf20Sopenharmony_ci		return 1;
34108c2ecf20Sopenharmony_ci	}
34118c2ecf20Sopenharmony_ci
34128c2ecf20Sopenharmony_ci	err = 0;
34138c2ecf20Sopenharmony_ci	type = GETTYPE(op.type);
34148c2ecf20Sopenharmony_ci
34158c2ecf20Sopenharmony_ci	if (OP_IS_LOAD_STORE(type)) {
34168c2ecf20Sopenharmony_ci		err = emulate_loadstore(regs, &op);
34178c2ecf20Sopenharmony_ci		if (err)
34188c2ecf20Sopenharmony_ci			return 0;
34198c2ecf20Sopenharmony_ci		goto instr_done;
34208c2ecf20Sopenharmony_ci	}
34218c2ecf20Sopenharmony_ci
34228c2ecf20Sopenharmony_ci	switch (type) {
34238c2ecf20Sopenharmony_ci	case CACHEOP:
34248c2ecf20Sopenharmony_ci		ea = truncate_if_32bit(regs->msr, op.ea);
34258c2ecf20Sopenharmony_ci		if (!address_ok(regs, ea, 8))
34268c2ecf20Sopenharmony_ci			return 0;
34278c2ecf20Sopenharmony_ci		switch (op.type & CACHEOP_MASK) {
34288c2ecf20Sopenharmony_ci		case DCBST:
34298c2ecf20Sopenharmony_ci			__cacheop_user_asmx(ea, err, "dcbst");
34308c2ecf20Sopenharmony_ci			break;
34318c2ecf20Sopenharmony_ci		case DCBF:
34328c2ecf20Sopenharmony_ci			__cacheop_user_asmx(ea, err, "dcbf");
34338c2ecf20Sopenharmony_ci			break;
34348c2ecf20Sopenharmony_ci		case DCBTST:
34358c2ecf20Sopenharmony_ci			if (op.reg == 0)
34368c2ecf20Sopenharmony_ci				prefetchw((void *) ea);
34378c2ecf20Sopenharmony_ci			break;
34388c2ecf20Sopenharmony_ci		case DCBT:
34398c2ecf20Sopenharmony_ci			if (op.reg == 0)
34408c2ecf20Sopenharmony_ci				prefetch((void *) ea);
34418c2ecf20Sopenharmony_ci			break;
34428c2ecf20Sopenharmony_ci		case ICBI:
34438c2ecf20Sopenharmony_ci			__cacheop_user_asmx(ea, err, "icbi");
34448c2ecf20Sopenharmony_ci			break;
34458c2ecf20Sopenharmony_ci		case DCBZ:
34468c2ecf20Sopenharmony_ci			err = emulate_dcbz(ea, regs);
34478c2ecf20Sopenharmony_ci			break;
34488c2ecf20Sopenharmony_ci		}
34498c2ecf20Sopenharmony_ci		if (err) {
34508c2ecf20Sopenharmony_ci			regs->dar = ea;
34518c2ecf20Sopenharmony_ci			return 0;
34528c2ecf20Sopenharmony_ci		}
34538c2ecf20Sopenharmony_ci		goto instr_done;
34548c2ecf20Sopenharmony_ci
34558c2ecf20Sopenharmony_ci	case MFMSR:
34568c2ecf20Sopenharmony_ci		regs->gpr[op.reg] = regs->msr & MSR_MASK;
34578c2ecf20Sopenharmony_ci		goto instr_done;
34588c2ecf20Sopenharmony_ci
34598c2ecf20Sopenharmony_ci	case MTMSR:
34608c2ecf20Sopenharmony_ci		val = regs->gpr[op.reg];
34618c2ecf20Sopenharmony_ci		if ((val & MSR_RI) == 0)
34628c2ecf20Sopenharmony_ci			/* can't step mtmsr[d] that would clear MSR_RI */
34638c2ecf20Sopenharmony_ci			return -1;
34648c2ecf20Sopenharmony_ci		/* here op.val is the mask of bits to change */
34658c2ecf20Sopenharmony_ci		regs->msr = (regs->msr & ~op.val) | (val & op.val);
34668c2ecf20Sopenharmony_ci		goto instr_done;
34678c2ecf20Sopenharmony_ci
34688c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64
34698c2ecf20Sopenharmony_ci	case SYSCALL:	/* sc */
34708c2ecf20Sopenharmony_ci		/*
34718c2ecf20Sopenharmony_ci		 * N.B. this uses knowledge about how the syscall
34728c2ecf20Sopenharmony_ci		 * entry code works.  If that is changed, this will
34738c2ecf20Sopenharmony_ci		 * need to be changed also.
34748c2ecf20Sopenharmony_ci		 */
34758c2ecf20Sopenharmony_ci		if (IS_ENABLED(CONFIG_PPC_FAST_ENDIAN_SWITCH) &&
34768c2ecf20Sopenharmony_ci				cpu_has_feature(CPU_FTR_REAL_LE) &&
34778c2ecf20Sopenharmony_ci				regs->gpr[0] == 0x1ebe) {
34788c2ecf20Sopenharmony_ci			regs->msr ^= MSR_LE;
34798c2ecf20Sopenharmony_ci			goto instr_done;
34808c2ecf20Sopenharmony_ci		}
34818c2ecf20Sopenharmony_ci		regs->gpr[9] = regs->gpr[13];
34828c2ecf20Sopenharmony_ci		regs->gpr[10] = MSR_KERNEL;
34838c2ecf20Sopenharmony_ci		regs->gpr[11] = regs->nip + 4;
34848c2ecf20Sopenharmony_ci		regs->gpr[12] = regs->msr & MSR_MASK;
34858c2ecf20Sopenharmony_ci		regs->gpr[13] = (unsigned long) get_paca();
34868c2ecf20Sopenharmony_ci		regs->nip = (unsigned long) &system_call_common;
34878c2ecf20Sopenharmony_ci		regs->msr = MSR_KERNEL;
34888c2ecf20Sopenharmony_ci		return 1;
34898c2ecf20Sopenharmony_ci
34908c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC_BOOK3S_64
34918c2ecf20Sopenharmony_ci	case SYSCALL_VECTORED_0:	/* scv 0 */
34928c2ecf20Sopenharmony_ci		regs->gpr[9] = regs->gpr[13];
34938c2ecf20Sopenharmony_ci		regs->gpr[10] = MSR_KERNEL;
34948c2ecf20Sopenharmony_ci		regs->gpr[11] = regs->nip + 4;
34958c2ecf20Sopenharmony_ci		regs->gpr[12] = regs->msr & MSR_MASK;
34968c2ecf20Sopenharmony_ci		regs->gpr[13] = (unsigned long) get_paca();
34978c2ecf20Sopenharmony_ci		regs->nip = (unsigned long) &system_call_vectored_emulate;
34988c2ecf20Sopenharmony_ci		regs->msr = MSR_KERNEL;
34998c2ecf20Sopenharmony_ci		return 1;
35008c2ecf20Sopenharmony_ci#endif
35018c2ecf20Sopenharmony_ci
35028c2ecf20Sopenharmony_ci	case RFI:
35038c2ecf20Sopenharmony_ci		return -1;
35048c2ecf20Sopenharmony_ci#endif
35058c2ecf20Sopenharmony_ci	}
35068c2ecf20Sopenharmony_ci	return 0;
35078c2ecf20Sopenharmony_ci
35088c2ecf20Sopenharmony_ci instr_done:
35098c2ecf20Sopenharmony_ci	regs->nip = truncate_if_32bit(regs->msr, regs->nip + GETLENGTH(op.type));
35108c2ecf20Sopenharmony_ci	return 1;
35118c2ecf20Sopenharmony_ci}
35128c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(emulate_step);
3513