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
12int 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
46int 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
118int 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