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