Merge branches 'fixes' and 'misc' into for-next
[linux.git] / arch / arm / kernel / kprobes-common.c
1 /*
2  * arch/arm/kernel/kprobes-common.c
3  *
4  * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>.
5  *
6  * Some contents moved here from arch/arm/include/asm/kprobes-arm.c which is
7  * Copyright (C) 2006, 2007 Motorola Inc.
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License version 2 as
11  * published by the Free Software Foundation.
12  */
13
14 #include <linux/kernel.h>
15 #include <linux/kprobes.h>
16
17 #include "kprobes.h"
18
19
20 static void __kprobes simulate_ldm1stm1(probes_opcode_t insn,
21                 struct arch_probes_insn *asi,
22                 struct pt_regs *regs)
23 {
24         int rn = (insn >> 16) & 0xf;
25         int lbit = insn & (1 << 20);
26         int wbit = insn & (1 << 21);
27         int ubit = insn & (1 << 23);
28         int pbit = insn & (1 << 24);
29         long *addr = (long *)regs->uregs[rn];
30         int reg_bit_vector;
31         int reg_count;
32
33         reg_count = 0;
34         reg_bit_vector = insn & 0xffff;
35         while (reg_bit_vector) {
36                 reg_bit_vector &= (reg_bit_vector - 1);
37                 ++reg_count;
38         }
39
40         if (!ubit)
41                 addr -= reg_count;
42         addr += (!pbit == !ubit);
43
44         reg_bit_vector = insn & 0xffff;
45         while (reg_bit_vector) {
46                 int reg = __ffs(reg_bit_vector);
47                 reg_bit_vector &= (reg_bit_vector - 1);
48                 if (lbit)
49                         regs->uregs[reg] = *addr++;
50                 else
51                         *addr++ = regs->uregs[reg];
52         }
53
54         if (wbit) {
55                 if (!ubit)
56                         addr -= reg_count;
57                 addr -= (!pbit == !ubit);
58                 regs->uregs[rn] = (long)addr;
59         }
60 }
61
62 static void __kprobes simulate_stm1_pc(probes_opcode_t insn,
63         struct arch_probes_insn *asi,
64         struct pt_regs *regs)
65 {
66         unsigned long addr = regs->ARM_pc - 4;
67
68         regs->ARM_pc = (long)addr + str_pc_offset;
69         simulate_ldm1stm1(insn, asi, regs);
70         regs->ARM_pc = (long)addr + 4;
71 }
72
73 static void __kprobes simulate_ldm1_pc(probes_opcode_t insn,
74         struct arch_probes_insn *asi,
75         struct pt_regs *regs)
76 {
77         simulate_ldm1stm1(insn, asi, regs);
78         load_write_pc(regs->ARM_pc, regs);
79 }
80
81 static void __kprobes
82 emulate_generic_r0_12_noflags(probes_opcode_t insn,
83         struct arch_probes_insn *asi, struct pt_regs *regs)
84 {
85         register void *rregs asm("r1") = regs;
86         register void *rfn asm("lr") = asi->insn_fn;
87
88         __asm__ __volatile__ (
89                 "stmdb  sp!, {%[regs], r11}     \n\t"
90                 "ldmia  %[regs], {r0-r12}       \n\t"
91 #if __LINUX_ARM_ARCH__ >= 6
92                 "blx    %[fn]                   \n\t"
93 #else
94                 "str    %[fn], [sp, #-4]!       \n\t"
95                 "adr    lr, 1f                  \n\t"
96                 "ldr    pc, [sp], #4            \n\t"
97                 "1:                             \n\t"
98 #endif
99                 "ldr    lr, [sp], #4            \n\t" /* lr = regs */
100                 "stmia  lr, {r0-r12}            \n\t"
101                 "ldr    r11, [sp], #4           \n\t"
102                 : [regs] "=r" (rregs), [fn] "=r" (rfn)
103                 : "0" (rregs), "1" (rfn)
104                 : "r0", "r2", "r3", "r4", "r5", "r6", "r7",
105                   "r8", "r9", "r10", "r12", "memory", "cc"
106                 );
107 }
108
109 static void __kprobes
110 emulate_generic_r2_14_noflags(probes_opcode_t insn,
111         struct arch_probes_insn *asi, struct pt_regs *regs)
112 {
113         emulate_generic_r0_12_noflags(insn, asi,
114                 (struct pt_regs *)(regs->uregs+2));
115 }
116
117 static void __kprobes
118 emulate_ldm_r3_15(probes_opcode_t insn,
119         struct arch_probes_insn *asi, struct pt_regs *regs)
120 {
121         emulate_generic_r0_12_noflags(insn, asi,
122                 (struct pt_regs *)(regs->uregs+3));
123         load_write_pc(regs->ARM_pc, regs);
124 }
125
126 enum probes_insn __kprobes
127 kprobe_decode_ldmstm(probes_opcode_t insn, struct arch_probes_insn *asi,
128                 const struct decode_header *h)
129 {
130         probes_insn_handler_t *handler = 0;
131         unsigned reglist = insn & 0xffff;
132         int is_ldm = insn & 0x100000;
133         int rn = (insn >> 16) & 0xf;
134
135         if (rn <= 12 && (reglist & 0xe000) == 0) {
136                 /* Instruction only uses registers in the range R0..R12 */
137                 handler = emulate_generic_r0_12_noflags;
138
139         } else if (rn >= 2 && (reglist & 0x8003) == 0) {
140                 /* Instruction only uses registers in the range R2..R14 */
141                 rn -= 2;
142                 reglist >>= 2;
143                 handler = emulate_generic_r2_14_noflags;
144
145         } else if (rn >= 3 && (reglist & 0x0007) == 0) {
146                 /* Instruction only uses registers in the range R3..R15 */
147                 if (is_ldm && (reglist & 0x8000)) {
148                         rn -= 3;
149                         reglist >>= 3;
150                         handler = emulate_ldm_r3_15;
151                 }
152         }
153
154         if (handler) {
155                 /* We can emulate the instruction in (possibly) modified form */
156                 asi->insn[0] = (insn & 0xfff00000) | (rn << 16) | reglist;
157                 asi->insn_handler = handler;
158                 return INSN_GOOD;
159         }
160
161         /* Fallback to slower simulation... */
162         if (reglist & 0x8000)
163                 handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc;
164         else
165                 handler = simulate_ldm1stm1;
166         asi->insn_handler = handler;
167         return INSN_GOOD_NO_SLOT;
168 }
169