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, ®s->gpr[reg]); 6748c2ecf20Sopenharmony_ci } else { 6758c2ecf20Sopenharmony_ci err = read_mem(®s->gpr[reg + IS_LE], ea, 8, regs); 6768c2ecf20Sopenharmony_ci if (!err) 6778c2ecf20Sopenharmony_ci err = read_mem(®s->gpr[reg + IS_BE], ea + 8, 8, regs); 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci if (!err && unlikely(cross_endian)) 6808c2ecf20Sopenharmony_ci do_byte_reverse(®s->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(®->b[i], mem, read_size); 7378c2ecf20Sopenharmony_ci if (rev) 7388c2ecf20Sopenharmony_ci do_byte_reverse(®->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(®->fp[1 + IS_LE], 7468c2ecf20Sopenharmony_ci ®->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(®->dp[IS_LE], &buf.fp[1 + IS_LE]); 8288c2ecf20Sopenharmony_ci preempt_enable(); 8298c2ecf20Sopenharmony_ci reg = &buf; 8308c2ecf20Sopenharmony_ci } 8318c2ecf20Sopenharmony_ci memcpy(mem, ®->b[i], write_size); 8328c2ecf20Sopenharmony_ci if (size == 16) 8338c2ecf20Sopenharmony_ci memcpy(mem + 8, ®->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, ®s->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(®s->gpr[op->reg], ea, size, regs); 32408c2ecf20Sopenharmony_ci if (!err) { 32418c2ecf20Sopenharmony_ci if (op->type & SIGNEXT) 32428c2ecf20Sopenharmony_ci do_signext(®s->gpr[op->reg], size); 32438c2ecf20Sopenharmony_ci if ((op->type & BYTEREV) == (cross_endian ? 0 : BYTEREV)) 32448c2ecf20Sopenharmony_ci do_byterev(®s->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