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