diff options
author | Jan Willeke <willeke@de.ibm.com> | 2014-09-22 10:37:27 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2014-09-25 04:52:14 -0400 |
commit | 975fab17399a2b29985166181ad80e5f50fa42e9 (patch) | |
tree | 385dac7c1384947e5b3a520d40b60cb77d5797b1 | |
parent | bbae71bf9c2fe90dc5642d4cddbbc1994861fd92 (diff) |
s390/uprobes: common library for kprobes and uprobes
This patch moves common functions from kprobes.c to probes.c.
Thus its possible for uprobes to use them without enabling kprobes.
Signed-off-by: Jan Willeke <willeke@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/include/asm/kprobes.h | 4 | ||||
-rw-r--r-- | arch/s390/kernel/kprobes.c | 154 | ||||
-rw-r--r-- | arch/s390/lib/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/lib/probes.c | 159 |
4 files changed, 168 insertions, 151 deletions
diff --git a/arch/s390/include/asm/kprobes.h b/arch/s390/include/asm/kprobes.h index 4176dfe0fba1..98629173ce3b 100644 --- a/arch/s390/include/asm/kprobes.h +++ b/arch/s390/include/asm/kprobes.h | |||
@@ -84,6 +84,10 @@ int kprobe_fault_handler(struct pt_regs *regs, int trapnr); | |||
84 | int kprobe_exceptions_notify(struct notifier_block *self, | 84 | int kprobe_exceptions_notify(struct notifier_block *self, |
85 | unsigned long val, void *data); | 85 | unsigned long val, void *data); |
86 | 86 | ||
87 | int probe_is_prohibited_opcode(u16 *insn); | ||
88 | int probe_get_fixup_type(u16 *insn); | ||
89 | int probe_is_insn_relative_long(u16 *insn); | ||
90 | |||
87 | #define flush_insn_slot(p) do { } while (0) | 91 | #define flush_insn_slot(p) do { } while (0) |
88 | 92 | ||
89 | #endif /* _ASM_S390_KPROBES_H */ | 93 | #endif /* _ASM_S390_KPROBES_H */ |
diff --git a/arch/s390/kernel/kprobes.c b/arch/s390/kernel/kprobes.c index c48a00c9f351..27ae5433fe4d 100644 --- a/arch/s390/kernel/kprobes.c +++ b/arch/s390/kernel/kprobes.c | |||
@@ -58,161 +58,13 @@ struct kprobe_insn_cache kprobe_dmainsn_slots = { | |||
58 | .insn_size = MAX_INSN_SIZE, | 58 | .insn_size = MAX_INSN_SIZE, |
59 | }; | 59 | }; |
60 | 60 | ||
61 | static int __kprobes is_prohibited_opcode(kprobe_opcode_t *insn) | ||
62 | { | ||
63 | if (!is_known_insn((unsigned char *)insn)) | ||
64 | return -EINVAL; | ||
65 | switch (insn[0] >> 8) { | ||
66 | case 0x0c: /* bassm */ | ||
67 | case 0x0b: /* bsm */ | ||
68 | case 0x83: /* diag */ | ||
69 | case 0x44: /* ex */ | ||
70 | case 0xac: /* stnsm */ | ||
71 | case 0xad: /* stosm */ | ||
72 | return -EINVAL; | ||
73 | case 0xc6: | ||
74 | switch (insn[0] & 0x0f) { | ||
75 | case 0x00: /* exrl */ | ||
76 | return -EINVAL; | ||
77 | } | ||
78 | } | ||
79 | switch (insn[0]) { | ||
80 | case 0x0101: /* pr */ | ||
81 | case 0xb25a: /* bsa */ | ||
82 | case 0xb240: /* bakr */ | ||
83 | case 0xb258: /* bsg */ | ||
84 | case 0xb218: /* pc */ | ||
85 | case 0xb228: /* pt */ | ||
86 | case 0xb98d: /* epsw */ | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static int __kprobes get_fixup_type(kprobe_opcode_t *insn) | ||
93 | { | ||
94 | /* default fixup method */ | ||
95 | int fixup = FIXUP_PSW_NORMAL; | ||
96 | |||
97 | switch (insn[0] >> 8) { | ||
98 | case 0x05: /* balr */ | ||
99 | case 0x0d: /* basr */ | ||
100 | fixup = FIXUP_RETURN_REGISTER; | ||
101 | /* if r2 = 0, no branch will be taken */ | ||
102 | if ((insn[0] & 0x0f) == 0) | ||
103 | fixup |= FIXUP_BRANCH_NOT_TAKEN; | ||
104 | break; | ||
105 | case 0x06: /* bctr */ | ||
106 | case 0x07: /* bcr */ | ||
107 | fixup = FIXUP_BRANCH_NOT_TAKEN; | ||
108 | break; | ||
109 | case 0x45: /* bal */ | ||
110 | case 0x4d: /* bas */ | ||
111 | fixup = FIXUP_RETURN_REGISTER; | ||
112 | break; | ||
113 | case 0x47: /* bc */ | ||
114 | case 0x46: /* bct */ | ||
115 | case 0x86: /* bxh */ | ||
116 | case 0x87: /* bxle */ | ||
117 | fixup = FIXUP_BRANCH_NOT_TAKEN; | ||
118 | break; | ||
119 | case 0x82: /* lpsw */ | ||
120 | fixup = FIXUP_NOT_REQUIRED; | ||
121 | break; | ||
122 | case 0xb2: /* lpswe */ | ||
123 | if ((insn[0] & 0xff) == 0xb2) | ||
124 | fixup = FIXUP_NOT_REQUIRED; | ||
125 | break; | ||
126 | case 0xa7: /* bras */ | ||
127 | if ((insn[0] & 0x0f) == 0x05) | ||
128 | fixup |= FIXUP_RETURN_REGISTER; | ||
129 | break; | ||
130 | case 0xc0: | ||
131 | if ((insn[0] & 0x0f) == 0x05) /* brasl */ | ||
132 | fixup |= FIXUP_RETURN_REGISTER; | ||
133 | break; | ||
134 | case 0xeb: | ||
135 | switch (insn[2] & 0xff) { | ||
136 | case 0x44: /* bxhg */ | ||
137 | case 0x45: /* bxleg */ | ||
138 | fixup = FIXUP_BRANCH_NOT_TAKEN; | ||
139 | break; | ||
140 | } | ||
141 | break; | ||
142 | case 0xe3: /* bctg */ | ||
143 | if ((insn[2] & 0xff) == 0x46) | ||
144 | fixup = FIXUP_BRANCH_NOT_TAKEN; | ||
145 | break; | ||
146 | case 0xec: | ||
147 | switch (insn[2] & 0xff) { | ||
148 | case 0xe5: /* clgrb */ | ||
149 | case 0xe6: /* cgrb */ | ||
150 | case 0xf6: /* crb */ | ||
151 | case 0xf7: /* clrb */ | ||
152 | case 0xfc: /* cgib */ | ||
153 | case 0xfd: /* cglib */ | ||
154 | case 0xfe: /* cib */ | ||
155 | case 0xff: /* clib */ | ||
156 | fixup = FIXUP_BRANCH_NOT_TAKEN; | ||
157 | break; | ||
158 | } | ||
159 | break; | ||
160 | } | ||
161 | return fixup; | ||
162 | } | ||
163 | |||
164 | static int __kprobes is_insn_relative_long(kprobe_opcode_t *insn) | ||
165 | { | ||
166 | /* Check if we have a RIL-b or RIL-c format instruction which | ||
167 | * we need to modify in order to avoid instruction emulation. */ | ||
168 | switch (insn[0] >> 8) { | ||
169 | case 0xc0: | ||
170 | if ((insn[0] & 0x0f) == 0x00) /* larl */ | ||
171 | return true; | ||
172 | break; | ||
173 | case 0xc4: | ||
174 | switch (insn[0] & 0x0f) { | ||
175 | case 0x02: /* llhrl */ | ||
176 | case 0x04: /* lghrl */ | ||
177 | case 0x05: /* lhrl */ | ||
178 | case 0x06: /* llghrl */ | ||
179 | case 0x07: /* sthrl */ | ||
180 | case 0x08: /* lgrl */ | ||
181 | case 0x0b: /* stgrl */ | ||
182 | case 0x0c: /* lgfrl */ | ||
183 | case 0x0d: /* lrl */ | ||
184 | case 0x0e: /* llgfrl */ | ||
185 | case 0x0f: /* strl */ | ||
186 | return true; | ||
187 | } | ||
188 | break; | ||
189 | case 0xc6: | ||
190 | switch (insn[0] & 0x0f) { | ||
191 | case 0x02: /* pfdrl */ | ||
192 | case 0x04: /* cghrl */ | ||
193 | case 0x05: /* chrl */ | ||
194 | case 0x06: /* clghrl */ | ||
195 | case 0x07: /* clhrl */ | ||
196 | case 0x08: /* cgrl */ | ||
197 | case 0x0a: /* clgrl */ | ||
198 | case 0x0c: /* cgfrl */ | ||
199 | case 0x0d: /* crl */ | ||
200 | case 0x0e: /* clgfrl */ | ||
201 | case 0x0f: /* clrl */ | ||
202 | return true; | ||
203 | } | ||
204 | break; | ||
205 | } | ||
206 | return false; | ||
207 | } | ||
208 | |||
209 | static void __kprobes copy_instruction(struct kprobe *p) | 61 | static void __kprobes copy_instruction(struct kprobe *p) |
210 | { | 62 | { |
211 | s64 disp, new_disp; | 63 | s64 disp, new_disp; |
212 | u64 addr, new_addr; | 64 | u64 addr, new_addr; |
213 | 65 | ||
214 | memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8)); | 66 | memcpy(p->ainsn.insn, p->addr, insn_length(p->opcode >> 8)); |
215 | if (!is_insn_relative_long(p->ainsn.insn)) | 67 | if (!probe_is_insn_relative_long(p->ainsn.insn)) |
216 | return; | 68 | return; |
217 | /* | 69 | /* |
218 | * For pc-relative instructions in RIL-b or RIL-c format patch the | 70 | * For pc-relative instructions in RIL-b or RIL-c format patch the |
@@ -276,7 +128,7 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
276 | if ((unsigned long) p->addr & 0x01) | 128 | if ((unsigned long) p->addr & 0x01) |
277 | return -EINVAL; | 129 | return -EINVAL; |
278 | /* Make sure the probe isn't going on a difficult instruction */ | 130 | /* Make sure the probe isn't going on a difficult instruction */ |
279 | if (is_prohibited_opcode(p->addr)) | 131 | if (probe_is_prohibited_opcode(p->addr)) |
280 | return -EINVAL; | 132 | return -EINVAL; |
281 | if (s390_get_insn_slot(p)) | 133 | if (s390_get_insn_slot(p)) |
282 | return -ENOMEM; | 134 | return -ENOMEM; |
@@ -605,7 +457,7 @@ static void __kprobes resume_execution(struct kprobe *p, struct pt_regs *regs) | |||
605 | { | 457 | { |
606 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 458 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
607 | unsigned long ip = regs->psw.addr & PSW_ADDR_INSN; | 459 | unsigned long ip = regs->psw.addr & PSW_ADDR_INSN; |
608 | int fixup = get_fixup_type(p->ainsn.insn); | 460 | int fixup = probe_get_fixup_type(p->ainsn.insn); |
609 | 461 | ||
610 | if (fixup & FIXUP_PSW_NORMAL) | 462 | if (fixup & FIXUP_PSW_NORMAL) |
611 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; | 463 | ip += (unsigned long) p->addr - (unsigned long) p->ainsn.insn; |
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index c6d752e8bf28..a01df233856f 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile | |||
@@ -6,3 +6,5 @@ lib-y += delay.o string.o uaccess.o find.o | |||
6 | obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o | 6 | obj-$(CONFIG_32BIT) += div64.o qrnnd.o ucmpdi2.o mem32.o |
7 | obj-$(CONFIG_64BIT) += mem64.o | 7 | obj-$(CONFIG_64BIT) += mem64.o |
8 | lib-$(CONFIG_SMP) += spinlock.o | 8 | lib-$(CONFIG_SMP) += spinlock.o |
9 | lib-$(CONFIG_KPROBES) += probes.o | ||
10 | lib-$(CONFIG_UPROBES) += probes.o | ||
diff --git a/arch/s390/lib/probes.c b/arch/s390/lib/probes.c new file mode 100644 index 000000000000..c5d64a099719 --- /dev/null +++ b/arch/s390/lib/probes.c | |||
@@ -0,0 +1,159 @@ | |||
1 | /* | ||
2 | * Common helper functions for kprobes and uprobes | ||
3 | * | ||
4 | * Copyright IBM Corp. 2014 | ||
5 | */ | ||
6 | |||
7 | #include <linux/kprobes.h> | ||
8 | #include <asm/dis.h> | ||
9 | |||
10 | int 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 | |||
44 | int 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 | |||
116 | int 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 | } | ||