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