1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0 2*4882a593Smuzhiyun /* 3*4882a593Smuzhiyun * Common helper functions for kprobes and uprobes 4*4882a593Smuzhiyun * 5*4882a593Smuzhiyun * Copyright IBM Corp. 2014 6*4882a593Smuzhiyun */ 7*4882a593Smuzhiyun 8*4882a593Smuzhiyun #include <linux/errno.h> 9*4882a593Smuzhiyun #include <asm/kprobes.h> 10*4882a593Smuzhiyun #include <asm/dis.h> 11*4882a593Smuzhiyun probe_is_prohibited_opcode(u16 * insn)12*4882a593Smuzhiyunint probe_is_prohibited_opcode(u16 *insn) 13*4882a593Smuzhiyun { 14*4882a593Smuzhiyun if (!is_known_insn((unsigned char *)insn)) 15*4882a593Smuzhiyun return -EINVAL; 16*4882a593Smuzhiyun switch (insn[0] >> 8) { 17*4882a593Smuzhiyun case 0x0c: /* bassm */ 18*4882a593Smuzhiyun case 0x0b: /* bsm */ 19*4882a593Smuzhiyun case 0x83: /* diag */ 20*4882a593Smuzhiyun case 0x44: /* ex */ 21*4882a593Smuzhiyun case 0xac: /* stnsm */ 22*4882a593Smuzhiyun case 0xad: /* stosm */ 23*4882a593Smuzhiyun return -EINVAL; 24*4882a593Smuzhiyun case 0xc6: 25*4882a593Smuzhiyun switch (insn[0] & 0x0f) { 26*4882a593Smuzhiyun case 0x00: /* exrl */ 27*4882a593Smuzhiyun return -EINVAL; 28*4882a593Smuzhiyun } 29*4882a593Smuzhiyun } 30*4882a593Smuzhiyun switch (insn[0]) { 31*4882a593Smuzhiyun case 0x0101: /* pr */ 32*4882a593Smuzhiyun case 0xb25a: /* bsa */ 33*4882a593Smuzhiyun case 0xb240: /* bakr */ 34*4882a593Smuzhiyun case 0xb258: /* bsg */ 35*4882a593Smuzhiyun case 0xb218: /* pc */ 36*4882a593Smuzhiyun case 0xb228: /* pt */ 37*4882a593Smuzhiyun case 0xb98d: /* epsw */ 38*4882a593Smuzhiyun case 0xe560: /* tbegin */ 39*4882a593Smuzhiyun case 0xe561: /* tbeginc */ 40*4882a593Smuzhiyun case 0xb2f8: /* tend */ 41*4882a593Smuzhiyun return -EINVAL; 42*4882a593Smuzhiyun } 43*4882a593Smuzhiyun return 0; 44*4882a593Smuzhiyun } 45*4882a593Smuzhiyun probe_get_fixup_type(u16 * insn)46*4882a593Smuzhiyunint probe_get_fixup_type(u16 *insn) 47*4882a593Smuzhiyun { 48*4882a593Smuzhiyun /* default fixup method */ 49*4882a593Smuzhiyun int fixup = FIXUP_PSW_NORMAL; 50*4882a593Smuzhiyun 51*4882a593Smuzhiyun switch (insn[0] >> 8) { 52*4882a593Smuzhiyun case 0x05: /* balr */ 53*4882a593Smuzhiyun case 0x0d: /* basr */ 54*4882a593Smuzhiyun fixup = FIXUP_RETURN_REGISTER; 55*4882a593Smuzhiyun /* if r2 = 0, no branch will be taken */ 56*4882a593Smuzhiyun if ((insn[0] & 0x0f) == 0) 57*4882a593Smuzhiyun fixup |= FIXUP_BRANCH_NOT_TAKEN; 58*4882a593Smuzhiyun break; 59*4882a593Smuzhiyun case 0x06: /* bctr */ 60*4882a593Smuzhiyun case 0x07: /* bcr */ 61*4882a593Smuzhiyun fixup = FIXUP_BRANCH_NOT_TAKEN; 62*4882a593Smuzhiyun break; 63*4882a593Smuzhiyun case 0x45: /* bal */ 64*4882a593Smuzhiyun case 0x4d: /* bas */ 65*4882a593Smuzhiyun fixup = FIXUP_RETURN_REGISTER; 66*4882a593Smuzhiyun break; 67*4882a593Smuzhiyun case 0x47: /* bc */ 68*4882a593Smuzhiyun case 0x46: /* bct */ 69*4882a593Smuzhiyun case 0x86: /* bxh */ 70*4882a593Smuzhiyun case 0x87: /* bxle */ 71*4882a593Smuzhiyun fixup = FIXUP_BRANCH_NOT_TAKEN; 72*4882a593Smuzhiyun break; 73*4882a593Smuzhiyun case 0x82: /* lpsw */ 74*4882a593Smuzhiyun fixup = FIXUP_NOT_REQUIRED; 75*4882a593Smuzhiyun break; 76*4882a593Smuzhiyun case 0xb2: /* lpswe */ 77*4882a593Smuzhiyun if ((insn[0] & 0xff) == 0xb2) 78*4882a593Smuzhiyun fixup = FIXUP_NOT_REQUIRED; 79*4882a593Smuzhiyun break; 80*4882a593Smuzhiyun case 0xa7: /* bras */ 81*4882a593Smuzhiyun if ((insn[0] & 0x0f) == 0x05) 82*4882a593Smuzhiyun fixup |= FIXUP_RETURN_REGISTER; 83*4882a593Smuzhiyun break; 84*4882a593Smuzhiyun case 0xc0: 85*4882a593Smuzhiyun if ((insn[0] & 0x0f) == 0x05) /* brasl */ 86*4882a593Smuzhiyun fixup |= FIXUP_RETURN_REGISTER; 87*4882a593Smuzhiyun break; 88*4882a593Smuzhiyun case 0xeb: 89*4882a593Smuzhiyun switch (insn[2] & 0xff) { 90*4882a593Smuzhiyun case 0x44: /* bxhg */ 91*4882a593Smuzhiyun case 0x45: /* bxleg */ 92*4882a593Smuzhiyun fixup = FIXUP_BRANCH_NOT_TAKEN; 93*4882a593Smuzhiyun break; 94*4882a593Smuzhiyun } 95*4882a593Smuzhiyun break; 96*4882a593Smuzhiyun case 0xe3: /* bctg */ 97*4882a593Smuzhiyun if ((insn[2] & 0xff) == 0x46) 98*4882a593Smuzhiyun fixup = FIXUP_BRANCH_NOT_TAKEN; 99*4882a593Smuzhiyun break; 100*4882a593Smuzhiyun case 0xec: 101*4882a593Smuzhiyun switch (insn[2] & 0xff) { 102*4882a593Smuzhiyun case 0xe5: /* clgrb */ 103*4882a593Smuzhiyun case 0xe6: /* cgrb */ 104*4882a593Smuzhiyun case 0xf6: /* crb */ 105*4882a593Smuzhiyun case 0xf7: /* clrb */ 106*4882a593Smuzhiyun case 0xfc: /* cgib */ 107*4882a593Smuzhiyun case 0xfd: /* cglib */ 108*4882a593Smuzhiyun case 0xfe: /* cib */ 109*4882a593Smuzhiyun case 0xff: /* clib */ 110*4882a593Smuzhiyun fixup = FIXUP_BRANCH_NOT_TAKEN; 111*4882a593Smuzhiyun break; 112*4882a593Smuzhiyun } 113*4882a593Smuzhiyun break; 114*4882a593Smuzhiyun } 115*4882a593Smuzhiyun return fixup; 116*4882a593Smuzhiyun } 117*4882a593Smuzhiyun probe_is_insn_relative_long(u16 * insn)118*4882a593Smuzhiyunint probe_is_insn_relative_long(u16 *insn) 119*4882a593Smuzhiyun { 120*4882a593Smuzhiyun /* Check if we have a RIL-b or RIL-c format instruction which 121*4882a593Smuzhiyun * we need to modify in order to avoid instruction emulation. */ 122*4882a593Smuzhiyun switch (insn[0] >> 8) { 123*4882a593Smuzhiyun case 0xc0: 124*4882a593Smuzhiyun if ((insn[0] & 0x0f) == 0x00) /* larl */ 125*4882a593Smuzhiyun return true; 126*4882a593Smuzhiyun break; 127*4882a593Smuzhiyun case 0xc4: 128*4882a593Smuzhiyun switch (insn[0] & 0x0f) { 129*4882a593Smuzhiyun case 0x02: /* llhrl */ 130*4882a593Smuzhiyun case 0x04: /* lghrl */ 131*4882a593Smuzhiyun case 0x05: /* lhrl */ 132*4882a593Smuzhiyun case 0x06: /* llghrl */ 133*4882a593Smuzhiyun case 0x07: /* sthrl */ 134*4882a593Smuzhiyun case 0x08: /* lgrl */ 135*4882a593Smuzhiyun case 0x0b: /* stgrl */ 136*4882a593Smuzhiyun case 0x0c: /* lgfrl */ 137*4882a593Smuzhiyun case 0x0d: /* lrl */ 138*4882a593Smuzhiyun case 0x0e: /* llgfrl */ 139*4882a593Smuzhiyun case 0x0f: /* strl */ 140*4882a593Smuzhiyun return true; 141*4882a593Smuzhiyun } 142*4882a593Smuzhiyun break; 143*4882a593Smuzhiyun case 0xc6: 144*4882a593Smuzhiyun switch (insn[0] & 0x0f) { 145*4882a593Smuzhiyun case 0x02: /* pfdrl */ 146*4882a593Smuzhiyun case 0x04: /* cghrl */ 147*4882a593Smuzhiyun case 0x05: /* chrl */ 148*4882a593Smuzhiyun case 0x06: /* clghrl */ 149*4882a593Smuzhiyun case 0x07: /* clhrl */ 150*4882a593Smuzhiyun case 0x08: /* cgrl */ 151*4882a593Smuzhiyun case 0x0a: /* clgrl */ 152*4882a593Smuzhiyun case 0x0c: /* cgfrl */ 153*4882a593Smuzhiyun case 0x0d: /* crl */ 154*4882a593Smuzhiyun case 0x0e: /* clgfrl */ 155*4882a593Smuzhiyun case 0x0f: /* clrl */ 156*4882a593Smuzhiyun return true; 157*4882a593Smuzhiyun } 158*4882a593Smuzhiyun break; 159*4882a593Smuzhiyun } 160*4882a593Smuzhiyun return false; 161*4882a593Smuzhiyun } 162