Linux-libre 4.17.3-gnu
[librecmc/linux-libre.git] / arch / s390 / lib / probes.c
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 }