Merge tag 'hwmon-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck...
[deliverable/linux.git] / arch / arm / kernel / uprobes-arm.c
1 /*
2 * Copyright (C) 2012 Rabin Vincent <rabin at rab.in>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9 #include <linux/kernel.h>
10 #include <linux/types.h>
11 #include <linux/stddef.h>
12 #include <linux/wait.h>
13 #include <linux/uprobes.h>
14 #include <linux/module.h>
15
16 #include "probes.h"
17 #include "probes-arm.h"
18 #include "uprobes.h"
19
20 static int uprobes_substitute_pc(unsigned long *pinsn, u32 oregs)
21 {
22 probes_opcode_t insn = __mem_to_opcode_arm(*pinsn);
23 probes_opcode_t temp;
24 probes_opcode_t mask;
25 int freereg;
26 u32 free = 0xffff;
27 u32 regs;
28
29 for (regs = oregs; regs; regs >>= 4, insn >>= 4) {
30 if ((regs & 0xf) == REG_TYPE_NONE)
31 continue;
32
33 free &= ~(1 << (insn & 0xf));
34 }
35
36 /* No PC, no problem */
37 if (free & (1 << 15))
38 return 15;
39
40 if (!free)
41 return -1;
42
43 /*
44 * fls instead of ffs ensures that for "ldrd r0, r1, [pc]" we would
45 * pick LR instead of R1.
46 */
47 freereg = free = fls(free) - 1;
48
49 temp = __mem_to_opcode_arm(*pinsn);
50 insn = temp;
51 regs = oregs;
52 mask = 0xf;
53
54 for (; regs; regs >>= 4, mask <<= 4, free <<= 4, temp >>= 4) {
55 if ((regs & 0xf) == REG_TYPE_NONE)
56 continue;
57
58 if ((temp & 0xf) != 15)
59 continue;
60
61 insn &= ~mask;
62 insn |= free & mask;
63 }
64
65 *pinsn = __opcode_to_mem_arm(insn);
66 return freereg;
67 }
68
69 static void uprobe_set_pc(struct arch_uprobe *auprobe,
70 struct arch_uprobe_task *autask,
71 struct pt_regs *regs)
72 {
73 u32 pcreg = auprobe->pcreg;
74
75 autask->backup = regs->uregs[pcreg];
76 regs->uregs[pcreg] = regs->ARM_pc + 8;
77 }
78
79 static void uprobe_unset_pc(struct arch_uprobe *auprobe,
80 struct arch_uprobe_task *autask,
81 struct pt_regs *regs)
82 {
83 /* PC will be taken care of by common code */
84 regs->uregs[auprobe->pcreg] = autask->backup;
85 }
86
87 static void uprobe_aluwrite_pc(struct arch_uprobe *auprobe,
88 struct arch_uprobe_task *autask,
89 struct pt_regs *regs)
90 {
91 u32 pcreg = auprobe->pcreg;
92
93 alu_write_pc(regs->uregs[pcreg], regs);
94 regs->uregs[pcreg] = autask->backup;
95 }
96
97 static void uprobe_write_pc(struct arch_uprobe *auprobe,
98 struct arch_uprobe_task *autask,
99 struct pt_regs *regs)
100 {
101 u32 pcreg = auprobe->pcreg;
102
103 load_write_pc(regs->uregs[pcreg], regs);
104 regs->uregs[pcreg] = autask->backup;
105 }
106
107 enum probes_insn
108 decode_pc_ro(probes_opcode_t insn, struct arch_probes_insn *asi,
109 const struct decode_header *d)
110 {
111 struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
112 asi);
113 struct decode_emulate *decode = (struct decode_emulate *) d;
114 u32 regs = decode->header.type_regs.bits >> DECODE_TYPE_BITS;
115 int reg;
116
117 reg = uprobes_substitute_pc(&auprobe->ixol[0], regs);
118 if (reg == 15)
119 return INSN_GOOD;
120
121 if (reg == -1)
122 return INSN_REJECTED;
123
124 auprobe->pcreg = reg;
125 auprobe->prehandler = uprobe_set_pc;
126 auprobe->posthandler = uprobe_unset_pc;
127
128 return INSN_GOOD;
129 }
130
131 enum probes_insn
132 decode_wb_pc(probes_opcode_t insn, struct arch_probes_insn *asi,
133 const struct decode_header *d, bool alu)
134 {
135 struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
136 asi);
137 enum probes_insn ret = decode_pc_ro(insn, asi, d);
138
139 if (((insn >> 12) & 0xf) == 15)
140 auprobe->posthandler = alu ? uprobe_aluwrite_pc
141 : uprobe_write_pc;
142
143 return ret;
144 }
145
146 enum probes_insn
147 decode_rd12rn16rm0rs8_rwflags(probes_opcode_t insn,
148 struct arch_probes_insn *asi,
149 const struct decode_header *d)
150 {
151 return decode_wb_pc(insn, asi, d, true);
152 }
153
154 enum probes_insn
155 decode_ldr(probes_opcode_t insn, struct arch_probes_insn *asi,
156 const struct decode_header *d)
157 {
158 return decode_wb_pc(insn, asi, d, false);
159 }
160
161 enum probes_insn
162 uprobe_decode_ldmstm(probes_opcode_t insn,
163 struct arch_probes_insn *asi,
164 const struct decode_header *d)
165 {
166 struct arch_uprobe *auprobe = container_of(asi, struct arch_uprobe,
167 asi);
168 unsigned reglist = insn & 0xffff;
169 int rn = (insn >> 16) & 0xf;
170 int lbit = insn & (1 << 20);
171 unsigned used = reglist | (1 << rn);
172
173 if (rn == 15)
174 return INSN_REJECTED;
175
176 if (!(used & (1 << 15)))
177 return INSN_GOOD;
178
179 if (used & (1 << 14))
180 return INSN_REJECTED;
181
182 /* Use LR instead of PC */
183 insn ^= 0xc000;
184
185 auprobe->pcreg = 14;
186 auprobe->ixol[0] = __opcode_to_mem_arm(insn);
187
188 auprobe->prehandler = uprobe_set_pc;
189 if (lbit)
190 auprobe->posthandler = uprobe_write_pc;
191 else
192 auprobe->posthandler = uprobe_unset_pc;
193
194 return INSN_GOOD;
195 }
196
197 const union decode_action uprobes_probes_actions[] = {
198 [PROBES_EMULATE_NONE] = {.handler = probes_simulate_nop},
199 [PROBES_SIMULATE_NOP] = {.handler = probes_simulate_nop},
200 [PROBES_PRELOAD_IMM] = {.handler = probes_simulate_nop},
201 [PROBES_PRELOAD_REG] = {.handler = probes_simulate_nop},
202 [PROBES_BRANCH_IMM] = {.handler = simulate_blx1},
203 [PROBES_MRS] = {.handler = simulate_mrs},
204 [PROBES_BRANCH_REG] = {.handler = simulate_blx2bx},
205 [PROBES_CLZ] = {.handler = probes_simulate_nop},
206 [PROBES_SATURATING_ARITHMETIC] = {.handler = probes_simulate_nop},
207 [PROBES_MUL1] = {.handler = probes_simulate_nop},
208 [PROBES_MUL2] = {.handler = probes_simulate_nop},
209 [PROBES_SWP] = {.handler = probes_simulate_nop},
210 [PROBES_LDRSTRD] = {.decoder = decode_pc_ro},
211 [PROBES_LOAD_EXTRA] = {.decoder = decode_pc_ro},
212 [PROBES_LOAD] = {.decoder = decode_ldr},
213 [PROBES_STORE_EXTRA] = {.decoder = decode_pc_ro},
214 [PROBES_STORE] = {.decoder = decode_pc_ro},
215 [PROBES_MOV_IP_SP] = {.handler = simulate_mov_ipsp},
216 [PROBES_DATA_PROCESSING_REG] = {
217 .decoder = decode_rd12rn16rm0rs8_rwflags},
218 [PROBES_DATA_PROCESSING_IMM] = {
219 .decoder = decode_rd12rn16rm0rs8_rwflags},
220 [PROBES_MOV_HALFWORD] = {.handler = probes_simulate_nop},
221 [PROBES_SEV] = {.handler = probes_simulate_nop},
222 [PROBES_WFE] = {.handler = probes_simulate_nop},
223 [PROBES_SATURATE] = {.handler = probes_simulate_nop},
224 [PROBES_REV] = {.handler = probes_simulate_nop},
225 [PROBES_MMI] = {.handler = probes_simulate_nop},
226 [PROBES_PACK] = {.handler = probes_simulate_nop},
227 [PROBES_EXTEND] = {.handler = probes_simulate_nop},
228 [PROBES_EXTEND_ADD] = {.handler = probes_simulate_nop},
229 [PROBES_MUL_ADD_LONG] = {.handler = probes_simulate_nop},
230 [PROBES_MUL_ADD] = {.handler = probes_simulate_nop},
231 [PROBES_BITFIELD] = {.handler = probes_simulate_nop},
232 [PROBES_BRANCH] = {.handler = simulate_bbl},
233 [PROBES_LDMSTM] = {.decoder = uprobe_decode_ldmstm}
234 };
This page took 0.036754 seconds and 5 git commands to generate.