162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Common helper functions for kprobes and uprobes 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright IBM Corp. 2014 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/errno.h> 962306a36Sopenharmony_ci#include <asm/kprobes.h> 1062306a36Sopenharmony_ci#include <asm/dis.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ciint probe_is_prohibited_opcode(u16 *insn) 1362306a36Sopenharmony_ci{ 1462306a36Sopenharmony_ci if (!is_known_insn((unsigned char *)insn)) 1562306a36Sopenharmony_ci return -EINVAL; 1662306a36Sopenharmony_ci switch (insn[0] >> 8) { 1762306a36Sopenharmony_ci case 0x0c: /* bassm */ 1862306a36Sopenharmony_ci case 0x0b: /* bsm */ 1962306a36Sopenharmony_ci case 0x83: /* diag */ 2062306a36Sopenharmony_ci case 0x44: /* ex */ 2162306a36Sopenharmony_ci case 0xac: /* stnsm */ 2262306a36Sopenharmony_ci case 0xad: /* stosm */ 2362306a36Sopenharmony_ci return -EINVAL; 2462306a36Sopenharmony_ci case 0xc6: 2562306a36Sopenharmony_ci switch (insn[0] & 0x0f) { 2662306a36Sopenharmony_ci case 0x00: /* exrl */ 2762306a36Sopenharmony_ci return -EINVAL; 2862306a36Sopenharmony_ci } 2962306a36Sopenharmony_ci } 3062306a36Sopenharmony_ci switch (insn[0]) { 3162306a36Sopenharmony_ci case 0x0101: /* pr */ 3262306a36Sopenharmony_ci case 0xb25a: /* bsa */ 3362306a36Sopenharmony_ci case 0xb240: /* bakr */ 3462306a36Sopenharmony_ci case 0xb258: /* bsg */ 3562306a36Sopenharmony_ci case 0xb218: /* pc */ 3662306a36Sopenharmony_ci case 0xb228: /* pt */ 3762306a36Sopenharmony_ci case 0xb98d: /* epsw */ 3862306a36Sopenharmony_ci case 0xe560: /* tbegin */ 3962306a36Sopenharmony_ci case 0xe561: /* tbeginc */ 4062306a36Sopenharmony_ci case 0xb2f8: /* tend */ 4162306a36Sopenharmony_ci return -EINVAL; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci return 0; 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ciint probe_get_fixup_type(u16 *insn) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci /* default fixup method */ 4962306a36Sopenharmony_ci int fixup = FIXUP_PSW_NORMAL; 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci switch (insn[0] >> 8) { 5262306a36Sopenharmony_ci case 0x05: /* balr */ 5362306a36Sopenharmony_ci case 0x0d: /* basr */ 5462306a36Sopenharmony_ci fixup = FIXUP_RETURN_REGISTER; 5562306a36Sopenharmony_ci /* if r2 = 0, no branch will be taken */ 5662306a36Sopenharmony_ci if ((insn[0] & 0x0f) == 0) 5762306a36Sopenharmony_ci fixup |= FIXUP_BRANCH_NOT_TAKEN; 5862306a36Sopenharmony_ci break; 5962306a36Sopenharmony_ci case 0x06: /* bctr */ 6062306a36Sopenharmony_ci case 0x07: /* bcr */ 6162306a36Sopenharmony_ci fixup = FIXUP_BRANCH_NOT_TAKEN; 6262306a36Sopenharmony_ci break; 6362306a36Sopenharmony_ci case 0x45: /* bal */ 6462306a36Sopenharmony_ci case 0x4d: /* bas */ 6562306a36Sopenharmony_ci fixup = FIXUP_RETURN_REGISTER; 6662306a36Sopenharmony_ci break; 6762306a36Sopenharmony_ci case 0x47: /* bc */ 6862306a36Sopenharmony_ci case 0x46: /* bct */ 6962306a36Sopenharmony_ci case 0x86: /* bxh */ 7062306a36Sopenharmony_ci case 0x87: /* bxle */ 7162306a36Sopenharmony_ci fixup = FIXUP_BRANCH_NOT_TAKEN; 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci case 0x82: /* lpsw */ 7462306a36Sopenharmony_ci fixup = FIXUP_NOT_REQUIRED; 7562306a36Sopenharmony_ci break; 7662306a36Sopenharmony_ci case 0xb2: /* lpswe */ 7762306a36Sopenharmony_ci if ((insn[0] & 0xff) == 0xb2) 7862306a36Sopenharmony_ci fixup = FIXUP_NOT_REQUIRED; 7962306a36Sopenharmony_ci break; 8062306a36Sopenharmony_ci case 0xa7: /* bras */ 8162306a36Sopenharmony_ci if ((insn[0] & 0x0f) == 0x05) 8262306a36Sopenharmony_ci fixup |= FIXUP_RETURN_REGISTER; 8362306a36Sopenharmony_ci break; 8462306a36Sopenharmony_ci case 0xc0: 8562306a36Sopenharmony_ci if ((insn[0] & 0x0f) == 0x05) /* brasl */ 8662306a36Sopenharmony_ci fixup |= FIXUP_RETURN_REGISTER; 8762306a36Sopenharmony_ci break; 8862306a36Sopenharmony_ci case 0xeb: 8962306a36Sopenharmony_ci switch (insn[2] & 0xff) { 9062306a36Sopenharmony_ci case 0x44: /* bxhg */ 9162306a36Sopenharmony_ci case 0x45: /* bxleg */ 9262306a36Sopenharmony_ci fixup = FIXUP_BRANCH_NOT_TAKEN; 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci } 9562306a36Sopenharmony_ci break; 9662306a36Sopenharmony_ci case 0xe3: /* bctg */ 9762306a36Sopenharmony_ci if ((insn[2] & 0xff) == 0x46) 9862306a36Sopenharmony_ci fixup = FIXUP_BRANCH_NOT_TAKEN; 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci case 0xec: 10162306a36Sopenharmony_ci switch (insn[2] & 0xff) { 10262306a36Sopenharmony_ci case 0xe5: /* clgrb */ 10362306a36Sopenharmony_ci case 0xe6: /* cgrb */ 10462306a36Sopenharmony_ci case 0xf6: /* crb */ 10562306a36Sopenharmony_ci case 0xf7: /* clrb */ 10662306a36Sopenharmony_ci case 0xfc: /* cgib */ 10762306a36Sopenharmony_ci case 0xfd: /* cglib */ 10862306a36Sopenharmony_ci case 0xfe: /* cib */ 10962306a36Sopenharmony_ci case 0xff: /* clib */ 11062306a36Sopenharmony_ci fixup = FIXUP_BRANCH_NOT_TAKEN; 11162306a36Sopenharmony_ci break; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci break; 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci return fixup; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ciint probe_is_insn_relative_long(u16 *insn) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci /* Check if we have a RIL-b or RIL-c format instruction which 12162306a36Sopenharmony_ci * we need to modify in order to avoid instruction emulation. */ 12262306a36Sopenharmony_ci switch (insn[0] >> 8) { 12362306a36Sopenharmony_ci case 0xc0: 12462306a36Sopenharmony_ci if ((insn[0] & 0x0f) == 0x00) /* larl */ 12562306a36Sopenharmony_ci return true; 12662306a36Sopenharmony_ci break; 12762306a36Sopenharmony_ci case 0xc4: 12862306a36Sopenharmony_ci switch (insn[0] & 0x0f) { 12962306a36Sopenharmony_ci case 0x02: /* llhrl */ 13062306a36Sopenharmony_ci case 0x04: /* lghrl */ 13162306a36Sopenharmony_ci case 0x05: /* lhrl */ 13262306a36Sopenharmony_ci case 0x06: /* llghrl */ 13362306a36Sopenharmony_ci case 0x07: /* sthrl */ 13462306a36Sopenharmony_ci case 0x08: /* lgrl */ 13562306a36Sopenharmony_ci case 0x0b: /* stgrl */ 13662306a36Sopenharmony_ci case 0x0c: /* lgfrl */ 13762306a36Sopenharmony_ci case 0x0d: /* lrl */ 13862306a36Sopenharmony_ci case 0x0e: /* llgfrl */ 13962306a36Sopenharmony_ci case 0x0f: /* strl */ 14062306a36Sopenharmony_ci return true; 14162306a36Sopenharmony_ci } 14262306a36Sopenharmony_ci break; 14362306a36Sopenharmony_ci case 0xc6: 14462306a36Sopenharmony_ci switch (insn[0] & 0x0f) { 14562306a36Sopenharmony_ci case 0x02: /* pfdrl */ 14662306a36Sopenharmony_ci case 0x04: /* cghrl */ 14762306a36Sopenharmony_ci case 0x05: /* chrl */ 14862306a36Sopenharmony_ci case 0x06: /* clghrl */ 14962306a36Sopenharmony_ci case 0x07: /* clhrl */ 15062306a36Sopenharmony_ci case 0x08: /* cgrl */ 15162306a36Sopenharmony_ci case 0x0a: /* clgrl */ 15262306a36Sopenharmony_ci case 0x0c: /* cgfrl */ 15362306a36Sopenharmony_ci case 0x0d: /* crl */ 15462306a36Sopenharmony_ci case 0x0e: /* clgfrl */ 15562306a36Sopenharmony_ci case 0x0f: /* clrl */ 15662306a36Sopenharmony_ci return true; 15762306a36Sopenharmony_ci } 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci return false; 16162306a36Sopenharmony_ci} 162