diff options
Diffstat (limited to 'arch/arm')
65 files changed, 3909 insertions, 1850 deletions
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig index 9adc278a22ab..68b456129bef 100644 --- a/arch/arm/Kconfig +++ b/arch/arm/Kconfig | |||
@@ -10,7 +10,7 @@ config ARM | |||
10 | select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) | 10 | select GENERIC_ATOMIC64 if (CPU_V6 || !CPU_32v6K || !AEABI) |
11 | select HAVE_OPROFILE if (HAVE_PERF_EVENTS) | 11 | select HAVE_OPROFILE if (HAVE_PERF_EVENTS) |
12 | select HAVE_ARCH_KGDB | 12 | select HAVE_ARCH_KGDB |
13 | select HAVE_KPROBES if (!XIP_KERNEL && !THUMB2_KERNEL) | 13 | select HAVE_KPROBES if !XIP_KERNEL |
14 | select HAVE_KRETPROBES if (HAVE_KPROBES) | 14 | select HAVE_KRETPROBES if (HAVE_KPROBES) |
15 | select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) | 15 | select HAVE_FUNCTION_TRACER if (!XIP_KERNEL) |
16 | select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) | 16 | select HAVE_FTRACE_MCOUNT_RECORD if (!XIP_KERNEL) |
diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c index e5681636626f..841df7d21c2f 100644 --- a/arch/arm/common/dmabounce.c +++ b/arch/arm/common/dmabounce.c | |||
@@ -255,7 +255,7 @@ static inline dma_addr_t map_single(struct device *dev, void *ptr, size_t size, | |||
255 | if (buf == 0) { | 255 | if (buf == 0) { |
256 | dev_err(dev, "%s: unable to map unsafe buffer %p!\n", | 256 | dev_err(dev, "%s: unable to map unsafe buffer %p!\n", |
257 | __func__, ptr); | 257 | __func__, ptr); |
258 | return 0; | 258 | return ~0; |
259 | } | 259 | } |
260 | 260 | ||
261 | dev_dbg(dev, | 261 | dev_dbg(dev, |
diff --git a/arch/arm/include/asm/kprobes.h b/arch/arm/include/asm/kprobes.h index e46bdd0097eb..feec86768f9c 100644 --- a/arch/arm/include/asm/kprobes.h +++ b/arch/arm/include/asm/kprobes.h | |||
@@ -24,12 +24,6 @@ | |||
24 | #define MAX_INSN_SIZE 2 | 24 | #define MAX_INSN_SIZE 2 |
25 | #define MAX_STACK_SIZE 64 /* 32 would probably be OK */ | 25 | #define MAX_STACK_SIZE 64 /* 32 would probably be OK */ |
26 | 26 | ||
27 | /* | ||
28 | * This undefined instruction must be unique and | ||
29 | * reserved solely for kprobes' use. | ||
30 | */ | ||
31 | #define KPROBE_BREAKPOINT_INSTRUCTION 0xe7f001f8 | ||
32 | |||
33 | #define regs_return_value(regs) ((regs)->ARM_r0) | 27 | #define regs_return_value(regs) ((regs)->ARM_r0) |
34 | #define flush_insn_slot(p) do { } while (0) | 28 | #define flush_insn_slot(p) do { } while (0) |
35 | #define kretprobe_blacklist_size 0 | 29 | #define kretprobe_blacklist_size 0 |
@@ -38,14 +32,17 @@ typedef u32 kprobe_opcode_t; | |||
38 | 32 | ||
39 | struct kprobe; | 33 | struct kprobe; |
40 | typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); | 34 | typedef void (kprobe_insn_handler_t)(struct kprobe *, struct pt_regs *); |
41 | |||
42 | typedef unsigned long (kprobe_check_cc)(unsigned long); | 35 | typedef unsigned long (kprobe_check_cc)(unsigned long); |
36 | typedef void (kprobe_insn_singlestep_t)(struct kprobe *, struct pt_regs *); | ||
37 | typedef void (kprobe_insn_fn_t)(void); | ||
43 | 38 | ||
44 | /* Architecture specific copy of original instruction. */ | 39 | /* Architecture specific copy of original instruction. */ |
45 | struct arch_specific_insn { | 40 | struct arch_specific_insn { |
46 | kprobe_opcode_t *insn; | 41 | kprobe_opcode_t *insn; |
47 | kprobe_insn_handler_t *insn_handler; | 42 | kprobe_insn_handler_t *insn_handler; |
48 | kprobe_check_cc *insn_check_cc; | 43 | kprobe_check_cc *insn_check_cc; |
44 | kprobe_insn_singlestep_t *insn_singlestep; | ||
45 | kprobe_insn_fn_t *insn_fn; | ||
49 | }; | 46 | }; |
50 | 47 | ||
51 | struct prev_kprobe { | 48 | struct prev_kprobe { |
@@ -62,20 +59,9 @@ struct kprobe_ctlblk { | |||
62 | }; | 59 | }; |
63 | 60 | ||
64 | void arch_remove_kprobe(struct kprobe *); | 61 | void arch_remove_kprobe(struct kprobe *); |
65 | void kretprobe_trampoline(void); | ||
66 | |||
67 | int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr); | 62 | int kprobe_fault_handler(struct pt_regs *regs, unsigned int fsr); |
68 | int kprobe_exceptions_notify(struct notifier_block *self, | 63 | int kprobe_exceptions_notify(struct notifier_block *self, |
69 | unsigned long val, void *data); | 64 | unsigned long val, void *data); |
70 | 65 | ||
71 | enum kprobe_insn { | ||
72 | INSN_REJECTED, | ||
73 | INSN_GOOD, | ||
74 | INSN_GOOD_NO_SLOT | ||
75 | }; | ||
76 | |||
77 | enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, | ||
78 | struct arch_specific_insn *); | ||
79 | void __init arm_kprobe_decode_init(void); | ||
80 | 66 | ||
81 | #endif /* _ARM_KPROBES_H */ | 67 | #endif /* _ARM_KPROBES_H */ |
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h index 312d10877bd7..96187ff58c24 100644 --- a/arch/arm/include/asm/ptrace.h +++ b/arch/arm/include/asm/ptrace.h | |||
@@ -69,8 +69,9 @@ | |||
69 | #define PSR_c 0x000000ff /* Control */ | 69 | #define PSR_c 0x000000ff /* Control */ |
70 | 70 | ||
71 | /* | 71 | /* |
72 | * ARMv7 groups of APSR bits | 72 | * ARMv7 groups of PSR bits |
73 | */ | 73 | */ |
74 | #define APSR_MASK 0xf80f0000 /* N, Z, C, V, Q and GE flags */ | ||
74 | #define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ | 75 | #define PSR_ISET_MASK 0x01000010 /* ISA state (J, T) mask */ |
75 | #define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ | 76 | #define PSR_IT_MASK 0x0600fc00 /* If-Then execution state mask */ |
76 | #define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ | 77 | #define PSR_ENDIAN_MASK 0x00000200 /* Endianness state mask */ |
@@ -200,6 +201,14 @@ extern unsigned long profile_pc(struct pt_regs *regs); | |||
200 | #define PREDICATE_ALWAYS 0xe0000000 | 201 | #define PREDICATE_ALWAYS 0xe0000000 |
201 | 202 | ||
202 | /* | 203 | /* |
204 | * True if instr is a 32-bit thumb instruction. This works if instr | ||
205 | * is the first or only half-word of a thumb instruction. It also works | ||
206 | * when instr holds all 32-bits of a wide thumb instruction if stored | ||
207 | * in the form (first_half<<16)|(second_half) | ||
208 | */ | ||
209 | #define is_wide_instruction(instr) ((unsigned)(instr) >= 0xe800) | ||
210 | |||
211 | /* | ||
203 | * kprobe-based event tracer support | 212 | * kprobe-based event tracer support |
204 | */ | 213 | */ |
205 | #include <linux/stddef.h> | 214 | #include <linux/stddef.h> |
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile index a5b31af5c2b8..f7887dc53c1f 100644 --- a/arch/arm/kernel/Makefile +++ b/arch/arm/kernel/Makefile | |||
@@ -37,7 +37,12 @@ obj-$(CONFIG_HAVE_ARM_TWD) += smp_twd.o | |||
37 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o | 37 | obj-$(CONFIG_DYNAMIC_FTRACE) += ftrace.o |
38 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o | 38 | obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o |
39 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o | 39 | obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o |
40 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-decode.o | 40 | obj-$(CONFIG_KPROBES) += kprobes.o kprobes-common.o |
41 | ifdef CONFIG_THUMB2_KERNEL | ||
42 | obj-$(CONFIG_KPROBES) += kprobes-thumb.o | ||
43 | else | ||
44 | obj-$(CONFIG_KPROBES) += kprobes-arm.o | ||
45 | endif | ||
41 | obj-$(CONFIG_ATAGS_PROC) += atags.o | 46 | obj-$(CONFIG_ATAGS_PROC) += atags.o |
42 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o | 47 | obj-$(CONFIG_OABI_COMPAT) += sys_oabi-compat.o |
43 | obj-$(CONFIG_ARM_THUMBEE) += thumbee.o | 48 | obj-$(CONFIG_ARM_THUMBEE) += thumbee.o |
diff --git a/arch/arm/kernel/entry-header.S b/arch/arm/kernel/entry-header.S index 051166c2a932..83e29adced6c 100644 --- a/arch/arm/kernel/entry-header.S +++ b/arch/arm/kernel/entry-header.S | |||
@@ -121,15 +121,13 @@ | |||
121 | .endm | 121 | .endm |
122 | #else /* CONFIG_THUMB2_KERNEL */ | 122 | #else /* CONFIG_THUMB2_KERNEL */ |
123 | .macro svc_exit, rpsr | 123 | .macro svc_exit, rpsr |
124 | ldr lr, [sp, #S_SP] @ top of the stack | ||
125 | ldrd r0, r1, [sp, #S_LR] @ calling lr and pc | ||
124 | clrex @ clear the exclusive monitor | 126 | clrex @ clear the exclusive monitor |
125 | ldr r0, [sp, #S_SP] @ top of the stack | 127 | stmdb lr!, {r0, r1, \rpsr} @ calling lr and rfe context |
126 | ldr r1, [sp, #S_PC] @ return address | ||
127 | tst r0, #4 @ orig stack 8-byte aligned? | ||
128 | stmdb r0, {r1, \rpsr} @ rfe context | ||
129 | ldmia sp, {r0 - r12} | 128 | ldmia sp, {r0 - r12} |
130 | ldr lr, [sp, #S_LR] | 129 | mov sp, lr |
131 | addeq sp, sp, #S_FRAME_SIZE - 8 @ aligned | 130 | ldr lr, [sp], #4 |
132 | addne sp, sp, #S_FRAME_SIZE - 4 @ not aligned | ||
133 | rfeia sp! | 131 | rfeia sp! |
134 | .endm | 132 | .endm |
135 | 133 | ||
diff --git a/arch/arm/kernel/kprobes-arm.c b/arch/arm/kernel/kprobes-arm.c new file mode 100644 index 000000000000..79203ee1d039 --- /dev/null +++ b/arch/arm/kernel/kprobes-arm.c | |||
@@ -0,0 +1,999 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/kprobes-decode.c | ||
3 | * | ||
4 | * Copyright (C) 2006, 2007 Motorola Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * We do not have hardware single-stepping on ARM, This | ||
18 | * effort is further complicated by the ARM not having a | ||
19 | * "next PC" register. Instructions that change the PC | ||
20 | * can't be safely single-stepped in a MP environment, so | ||
21 | * we have a lot of work to do: | ||
22 | * | ||
23 | * In the prepare phase: | ||
24 | * *) If it is an instruction that does anything | ||
25 | * with the CPU mode, we reject it for a kprobe. | ||
26 | * (This is out of laziness rather than need. The | ||
27 | * instructions could be simulated.) | ||
28 | * | ||
29 | * *) Otherwise, decode the instruction rewriting its | ||
30 | * registers to take fixed, ordered registers and | ||
31 | * setting a handler for it to run the instruction. | ||
32 | * | ||
33 | * In the execution phase by an instruction's handler: | ||
34 | * | ||
35 | * *) If the PC is written to by the instruction, the | ||
36 | * instruction must be fully simulated in software. | ||
37 | * | ||
38 | * *) Otherwise, a modified form of the instruction is | ||
39 | * directly executed. Its handler calls the | ||
40 | * instruction in insn[0]. In insn[1] is a | ||
41 | * "mov pc, lr" to return. | ||
42 | * | ||
43 | * Before calling, load up the reordered registers | ||
44 | * from the original instruction's registers. If one | ||
45 | * of the original input registers is the PC, compute | ||
46 | * and adjust the appropriate input register. | ||
47 | * | ||
48 | * After call completes, copy the output registers to | ||
49 | * the original instruction's original registers. | ||
50 | * | ||
51 | * We don't use a real breakpoint instruction since that | ||
52 | * would have us in the kernel go from SVC mode to SVC | ||
53 | * mode losing the link register. Instead we use an | ||
54 | * undefined instruction. To simplify processing, the | ||
55 | * undefined instruction used for kprobes must be reserved | ||
56 | * exclusively for kprobes use. | ||
57 | * | ||
58 | * TODO: ifdef out some instruction decoding based on architecture. | ||
59 | */ | ||
60 | |||
61 | #include <linux/kernel.h> | ||
62 | #include <linux/kprobes.h> | ||
63 | |||
64 | #include "kprobes.h" | ||
65 | |||
66 | #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) | ||
67 | |||
68 | #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) | ||
69 | |||
70 | #if __LINUX_ARM_ARCH__ >= 6 | ||
71 | #define BLX(reg) "blx "reg" \n\t" | ||
72 | #else | ||
73 | #define BLX(reg) "mov lr, pc \n\t" \ | ||
74 | "mov pc, "reg" \n\t" | ||
75 | #endif | ||
76 | |||
77 | /* | ||
78 | * To avoid the complications of mimicing single-stepping on a | ||
79 | * processor without a Next-PC or a single-step mode, and to | ||
80 | * avoid having to deal with the side-effects of boosting, we | ||
81 | * simulate or emulate (almost) all ARM instructions. | ||
82 | * | ||
83 | * "Simulation" is where the instruction's behavior is duplicated in | ||
84 | * C code. "Emulation" is where the original instruction is rewritten | ||
85 | * and executed, often by altering its registers. | ||
86 | * | ||
87 | * By having all behavior of the kprobe'd instruction completed before | ||
88 | * returning from the kprobe_handler(), all locks (scheduler and | ||
89 | * interrupt) can safely be released. There is no need for secondary | ||
90 | * breakpoints, no race with MP or preemptable kernels, nor having to | ||
91 | * clean up resources counts at a later time impacting overall system | ||
92 | * performance. By rewriting the instruction, only the minimum registers | ||
93 | * need to be loaded and saved back optimizing performance. | ||
94 | * | ||
95 | * Calling the insnslot_*_rwflags version of a function doesn't hurt | ||
96 | * anything even when the CPSR flags aren't updated by the | ||
97 | * instruction. It's just a little slower in return for saving | ||
98 | * a little space by not having a duplicate function that doesn't | ||
99 | * update the flags. (The same optimization can be said for | ||
100 | * instructions that do or don't perform register writeback) | ||
101 | * Also, instructions can either read the flags, only write the | ||
102 | * flags, or read and write the flags. To save combinations | ||
103 | * rather than for sheer performance, flag functions just assume | ||
104 | * read and write of flags. | ||
105 | */ | ||
106 | |||
107 | static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) | ||
108 | { | ||
109 | kprobe_opcode_t insn = p->opcode; | ||
110 | long iaddr = (long)p->addr; | ||
111 | int disp = branch_displacement(insn); | ||
112 | |||
113 | if (insn & (1 << 24)) | ||
114 | regs->ARM_lr = iaddr + 4; | ||
115 | |||
116 | regs->ARM_pc = iaddr + 8 + disp; | ||
117 | } | ||
118 | |||
119 | static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) | ||
120 | { | ||
121 | kprobe_opcode_t insn = p->opcode; | ||
122 | long iaddr = (long)p->addr; | ||
123 | int disp = branch_displacement(insn); | ||
124 | |||
125 | regs->ARM_lr = iaddr + 4; | ||
126 | regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); | ||
127 | regs->ARM_cpsr |= PSR_T_BIT; | ||
128 | } | ||
129 | |||
130 | static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) | ||
131 | { | ||
132 | kprobe_opcode_t insn = p->opcode; | ||
133 | int rm = insn & 0xf; | ||
134 | long rmv = regs->uregs[rm]; | ||
135 | |||
136 | if (insn & (1 << 5)) | ||
137 | regs->ARM_lr = (long)p->addr + 4; | ||
138 | |||
139 | regs->ARM_pc = rmv & ~0x1; | ||
140 | regs->ARM_cpsr &= ~PSR_T_BIT; | ||
141 | if (rmv & 0x1) | ||
142 | regs->ARM_cpsr |= PSR_T_BIT; | ||
143 | } | ||
144 | |||
145 | static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) | ||
146 | { | ||
147 | kprobe_opcode_t insn = p->opcode; | ||
148 | int rd = (insn >> 12) & 0xf; | ||
149 | unsigned long mask = 0xf8ff03df; /* Mask out execution state */ | ||
150 | regs->uregs[rd] = regs->ARM_cpsr & mask; | ||
151 | } | ||
152 | |||
153 | static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) | ||
154 | { | ||
155 | regs->uregs[12] = regs->uregs[13]; | ||
156 | } | ||
157 | |||
158 | static void __kprobes | ||
159 | emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) | ||
160 | { | ||
161 | kprobe_opcode_t insn = p->opcode; | ||
162 | unsigned long pc = (unsigned long)p->addr + 8; | ||
163 | int rt = (insn >> 12) & 0xf; | ||
164 | int rn = (insn >> 16) & 0xf; | ||
165 | int rm = insn & 0xf; | ||
166 | |||
167 | register unsigned long rtv asm("r0") = regs->uregs[rt]; | ||
168 | register unsigned long rt2v asm("r1") = regs->uregs[rt+1]; | ||
169 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
170 | : regs->uregs[rn]; | ||
171 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
172 | |||
173 | __asm__ __volatile__ ( | ||
174 | BLX("%[fn]") | ||
175 | : "=r" (rtv), "=r" (rt2v), "=r" (rnv) | ||
176 | : "0" (rtv), "1" (rt2v), "2" (rnv), "r" (rmv), | ||
177 | [fn] "r" (p->ainsn.insn_fn) | ||
178 | : "lr", "memory", "cc" | ||
179 | ); | ||
180 | |||
181 | regs->uregs[rt] = rtv; | ||
182 | regs->uregs[rt+1] = rt2v; | ||
183 | if (is_writeback(insn)) | ||
184 | regs->uregs[rn] = rnv; | ||
185 | } | ||
186 | |||
187 | static void __kprobes | ||
188 | emulate_ldr(struct kprobe *p, struct pt_regs *regs) | ||
189 | { | ||
190 | kprobe_opcode_t insn = p->opcode; | ||
191 | unsigned long pc = (unsigned long)p->addr + 8; | ||
192 | int rt = (insn >> 12) & 0xf; | ||
193 | int rn = (insn >> 16) & 0xf; | ||
194 | int rm = insn & 0xf; | ||
195 | |||
196 | register unsigned long rtv asm("r0"); | ||
197 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
198 | : regs->uregs[rn]; | ||
199 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
200 | |||
201 | __asm__ __volatile__ ( | ||
202 | BLX("%[fn]") | ||
203 | : "=r" (rtv), "=r" (rnv) | ||
204 | : "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
205 | : "lr", "memory", "cc" | ||
206 | ); | ||
207 | |||
208 | if (rt == 15) | ||
209 | load_write_pc(rtv, regs); | ||
210 | else | ||
211 | regs->uregs[rt] = rtv; | ||
212 | |||
213 | if (is_writeback(insn)) | ||
214 | regs->uregs[rn] = rnv; | ||
215 | } | ||
216 | |||
217 | static void __kprobes | ||
218 | emulate_str(struct kprobe *p, struct pt_regs *regs) | ||
219 | { | ||
220 | kprobe_opcode_t insn = p->opcode; | ||
221 | unsigned long rtpc = (unsigned long)p->addr + str_pc_offset; | ||
222 | unsigned long rnpc = (unsigned long)p->addr + 8; | ||
223 | int rt = (insn >> 12) & 0xf; | ||
224 | int rn = (insn >> 16) & 0xf; | ||
225 | int rm = insn & 0xf; | ||
226 | |||
227 | register unsigned long rtv asm("r0") = (rt == 15) ? rtpc | ||
228 | : regs->uregs[rt]; | ||
229 | register unsigned long rnv asm("r2") = (rn == 15) ? rnpc | ||
230 | : regs->uregs[rn]; | ||
231 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
232 | |||
233 | __asm__ __volatile__ ( | ||
234 | BLX("%[fn]") | ||
235 | : "=r" (rnv) | ||
236 | : "r" (rtv), "0" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
237 | : "lr", "memory", "cc" | ||
238 | ); | ||
239 | |||
240 | if (is_writeback(insn)) | ||
241 | regs->uregs[rn] = rnv; | ||
242 | } | ||
243 | |||
244 | static void __kprobes | ||
245 | emulate_rd12rn16rm0rs8_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
246 | { | ||
247 | kprobe_opcode_t insn = p->opcode; | ||
248 | unsigned long pc = (unsigned long)p->addr + 8; | ||
249 | int rd = (insn >> 12) & 0xf; | ||
250 | int rn = (insn >> 16) & 0xf; | ||
251 | int rm = insn & 0xf; | ||
252 | int rs = (insn >> 8) & 0xf; | ||
253 | |||
254 | register unsigned long rdv asm("r0") = regs->uregs[rd]; | ||
255 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
256 | : regs->uregs[rn]; | ||
257 | register unsigned long rmv asm("r3") = (rm == 15) ? pc | ||
258 | : regs->uregs[rm]; | ||
259 | register unsigned long rsv asm("r1") = regs->uregs[rs]; | ||
260 | unsigned long cpsr = regs->ARM_cpsr; | ||
261 | |||
262 | __asm__ __volatile__ ( | ||
263 | "msr cpsr_fs, %[cpsr] \n\t" | ||
264 | BLX("%[fn]") | ||
265 | "mrs %[cpsr], cpsr \n\t" | ||
266 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
267 | : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), | ||
268 | "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
269 | : "lr", "memory", "cc" | ||
270 | ); | ||
271 | |||
272 | if (rd == 15) | ||
273 | alu_write_pc(rdv, regs); | ||
274 | else | ||
275 | regs->uregs[rd] = rdv; | ||
276 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
277 | } | ||
278 | |||
279 | static void __kprobes | ||
280 | emulate_rd12rn16rm0_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) | ||
281 | { | ||
282 | kprobe_opcode_t insn = p->opcode; | ||
283 | int rd = (insn >> 12) & 0xf; | ||
284 | int rn = (insn >> 16) & 0xf; | ||
285 | int rm = insn & 0xf; | ||
286 | |||
287 | register unsigned long rdv asm("r0") = regs->uregs[rd]; | ||
288 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
289 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
290 | unsigned long cpsr = regs->ARM_cpsr; | ||
291 | |||
292 | __asm__ __volatile__ ( | ||
293 | "msr cpsr_fs, %[cpsr] \n\t" | ||
294 | BLX("%[fn]") | ||
295 | "mrs %[cpsr], cpsr \n\t" | ||
296 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
297 | : "0" (rdv), "r" (rnv), "r" (rmv), | ||
298 | "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
299 | : "lr", "memory", "cc" | ||
300 | ); | ||
301 | |||
302 | regs->uregs[rd] = rdv; | ||
303 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
304 | } | ||
305 | |||
306 | static void __kprobes | ||
307 | emulate_rd16rn12rm0rs8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) | ||
308 | { | ||
309 | kprobe_opcode_t insn = p->opcode; | ||
310 | int rd = (insn >> 16) & 0xf; | ||
311 | int rn = (insn >> 12) & 0xf; | ||
312 | int rm = insn & 0xf; | ||
313 | int rs = (insn >> 8) & 0xf; | ||
314 | |||
315 | register unsigned long rdv asm("r2") = regs->uregs[rd]; | ||
316 | register unsigned long rnv asm("r0") = regs->uregs[rn]; | ||
317 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
318 | register unsigned long rsv asm("r1") = regs->uregs[rs]; | ||
319 | unsigned long cpsr = regs->ARM_cpsr; | ||
320 | |||
321 | __asm__ __volatile__ ( | ||
322 | "msr cpsr_fs, %[cpsr] \n\t" | ||
323 | BLX("%[fn]") | ||
324 | "mrs %[cpsr], cpsr \n\t" | ||
325 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
326 | : "0" (rdv), "r" (rnv), "r" (rmv), "r" (rsv), | ||
327 | "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
328 | : "lr", "memory", "cc" | ||
329 | ); | ||
330 | |||
331 | regs->uregs[rd] = rdv; | ||
332 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
333 | } | ||
334 | |||
335 | static void __kprobes | ||
336 | emulate_rd12rm0_noflags_nopc(struct kprobe *p, struct pt_regs *regs) | ||
337 | { | ||
338 | kprobe_opcode_t insn = p->opcode; | ||
339 | int rd = (insn >> 12) & 0xf; | ||
340 | int rm = insn & 0xf; | ||
341 | |||
342 | register unsigned long rdv asm("r0") = regs->uregs[rd]; | ||
343 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
344 | |||
345 | __asm__ __volatile__ ( | ||
346 | BLX("%[fn]") | ||
347 | : "=r" (rdv) | ||
348 | : "0" (rdv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
349 | : "lr", "memory", "cc" | ||
350 | ); | ||
351 | |||
352 | regs->uregs[rd] = rdv; | ||
353 | } | ||
354 | |||
355 | static void __kprobes | ||
356 | emulate_rdlo12rdhi16rn0rm8_rwflags_nopc(struct kprobe *p, struct pt_regs *regs) | ||
357 | { | ||
358 | kprobe_opcode_t insn = p->opcode; | ||
359 | int rdlo = (insn >> 12) & 0xf; | ||
360 | int rdhi = (insn >> 16) & 0xf; | ||
361 | int rn = insn & 0xf; | ||
362 | int rm = (insn >> 8) & 0xf; | ||
363 | |||
364 | register unsigned long rdlov asm("r0") = regs->uregs[rdlo]; | ||
365 | register unsigned long rdhiv asm("r2") = regs->uregs[rdhi]; | ||
366 | register unsigned long rnv asm("r3") = regs->uregs[rn]; | ||
367 | register unsigned long rmv asm("r1") = regs->uregs[rm]; | ||
368 | unsigned long cpsr = regs->ARM_cpsr; | ||
369 | |||
370 | __asm__ __volatile__ ( | ||
371 | "msr cpsr_fs, %[cpsr] \n\t" | ||
372 | BLX("%[fn]") | ||
373 | "mrs %[cpsr], cpsr \n\t" | ||
374 | : "=r" (rdlov), "=r" (rdhiv), [cpsr] "=r" (cpsr) | ||
375 | : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), | ||
376 | "2" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
377 | : "lr", "memory", "cc" | ||
378 | ); | ||
379 | |||
380 | regs->uregs[rdlo] = rdlov; | ||
381 | regs->uregs[rdhi] = rdhiv; | ||
382 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
383 | } | ||
384 | |||
385 | /* | ||
386 | * For the instruction masking and comparisons in all the "space_*" | ||
387 | * functions below, Do _not_ rearrange the order of tests unless | ||
388 | * you're very, very sure of what you are doing. For the sake of | ||
389 | * efficiency, the masks for some tests sometimes assume other test | ||
390 | * have been done prior to them so the number of patterns to test | ||
391 | * for an instruction set can be as broad as possible to reduce the | ||
392 | * number of tests needed. | ||
393 | */ | ||
394 | |||
395 | static const union decode_item arm_1111_table[] = { | ||
396 | /* Unconditional instructions */ | ||
397 | |||
398 | /* memory hint 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx */ | ||
399 | /* PLDI (immediate) 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx */ | ||
400 | /* PLDW (immediate) 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx */ | ||
401 | /* PLD (immediate) 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx */ | ||
402 | DECODE_SIMULATE (0xfe300000, 0xf4100000, kprobe_simulate_nop), | ||
403 | |||
404 | /* memory hint 1111 0110 x001 xxxx xxxx xxxx xxx0 xxxx */ | ||
405 | /* PLDI (register) 1111 0110 x101 xxxx xxxx xxxx xxx0 xxxx */ | ||
406 | /* PLDW (register) 1111 0111 x001 xxxx xxxx xxxx xxx0 xxxx */ | ||
407 | /* PLD (register) 1111 0111 x101 xxxx xxxx xxxx xxx0 xxxx */ | ||
408 | DECODE_SIMULATE (0xfe300010, 0xf6100000, kprobe_simulate_nop), | ||
409 | |||
410 | /* BLX (immediate) 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
411 | DECODE_SIMULATE (0xfe000000, 0xfa000000, simulate_blx1), | ||
412 | |||
413 | /* CPS 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ | ||
414 | /* SETEND 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ | ||
415 | /* SRS 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
416 | /* RFE 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
417 | |||
418 | /* Coprocessor instructions... */ | ||
419 | /* MCRR2 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
420 | /* MRRC2 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
421 | /* LDC2 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
422 | /* STC2 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
423 | /* CDP2 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
424 | /* MCR2 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
425 | /* MRC2 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
426 | |||
427 | /* Other unallocated instructions... */ | ||
428 | DECODE_END | ||
429 | }; | ||
430 | |||
431 | static const union decode_item arm_cccc_0001_0xx0____0xxx_table[] = { | ||
432 | /* Miscellaneous instructions */ | ||
433 | |||
434 | /* MRS cpsr cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ | ||
435 | DECODE_SIMULATEX(0x0ff000f0, 0x01000000, simulate_mrs, | ||
436 | REGS(0, NOPC, 0, 0, 0)), | ||
437 | |||
438 | /* BX cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ | ||
439 | DECODE_SIMULATE (0x0ff000f0, 0x01200010, simulate_blx2bx), | ||
440 | |||
441 | /* BLX (register) cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ | ||
442 | DECODE_SIMULATEX(0x0ff000f0, 0x01200030, simulate_blx2bx, | ||
443 | REGS(0, 0, 0, 0, NOPC)), | ||
444 | |||
445 | /* CLZ cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ | ||
446 | DECODE_EMULATEX (0x0ff000f0, 0x01600010, emulate_rd12rm0_noflags_nopc, | ||
447 | REGS(0, NOPC, 0, 0, NOPC)), | ||
448 | |||
449 | /* QADD cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx */ | ||
450 | /* QSUB cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx */ | ||
451 | /* QDADD cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx */ | ||
452 | /* QDSUB cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx */ | ||
453 | DECODE_EMULATEX (0x0f9000f0, 0x01000050, emulate_rd12rn16rm0_rwflags_nopc, | ||
454 | REGS(NOPC, NOPC, 0, 0, NOPC)), | ||
455 | |||
456 | /* BXJ cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ | ||
457 | /* MSR cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ | ||
458 | /* MRS spsr cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ | ||
459 | /* BKPT 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | ||
460 | /* SMC cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ | ||
461 | /* And unallocated instructions... */ | ||
462 | DECODE_END | ||
463 | }; | ||
464 | |||
465 | static const union decode_item arm_cccc_0001_0xx0____1xx0_table[] = { | ||
466 | /* Halfword multiply and multiply-accumulate */ | ||
467 | |||
468 | /* SMLALxy cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ | ||
469 | DECODE_EMULATEX (0x0ff00090, 0x01400080, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, | ||
470 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
471 | |||
472 | /* SMULWy cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ | ||
473 | DECODE_OR (0x0ff000b0, 0x012000a0), | ||
474 | /* SMULxy cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ | ||
475 | DECODE_EMULATEX (0x0ff00090, 0x01600080, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
476 | REGS(NOPC, 0, NOPC, 0, NOPC)), | ||
477 | |||
478 | /* SMLAxy cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx */ | ||
479 | DECODE_OR (0x0ff00090, 0x01000080), | ||
480 | /* SMLAWy cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx */ | ||
481 | DECODE_EMULATEX (0x0ff000b0, 0x01200080, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
482 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
483 | |||
484 | DECODE_END | ||
485 | }; | ||
486 | |||
487 | static const union decode_item arm_cccc_0000_____1001_table[] = { | ||
488 | /* Multiply and multiply-accumulate */ | ||
489 | |||
490 | /* MUL cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx */ | ||
491 | /* MULS cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx */ | ||
492 | DECODE_EMULATEX (0x0fe000f0, 0x00000090, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
493 | REGS(NOPC, 0, NOPC, 0, NOPC)), | ||
494 | |||
495 | /* MLA cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx */ | ||
496 | /* MLAS cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx */ | ||
497 | DECODE_OR (0x0fe000f0, 0x00200090), | ||
498 | /* MLS cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx */ | ||
499 | DECODE_EMULATEX (0x0ff000f0, 0x00600090, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
500 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
501 | |||
502 | /* UMAAL cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx */ | ||
503 | DECODE_OR (0x0ff000f0, 0x00400090), | ||
504 | /* UMULL cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx */ | ||
505 | /* UMULLS cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx */ | ||
506 | /* UMLAL cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx */ | ||
507 | /* UMLALS cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx */ | ||
508 | /* SMULL cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx */ | ||
509 | /* SMULLS cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx */ | ||
510 | /* SMLAL cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx */ | ||
511 | /* SMLALS cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx */ | ||
512 | DECODE_EMULATEX (0x0f8000f0, 0x00800090, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, | ||
513 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
514 | |||
515 | DECODE_END | ||
516 | }; | ||
517 | |||
518 | static const union decode_item arm_cccc_0001_____1001_table[] = { | ||
519 | /* Synchronization primitives */ | ||
520 | |||
521 | /* SMP/SWPB cccc 0001 0x00 xxxx xxxx xxxx 1001 xxxx */ | ||
522 | DECODE_EMULATEX (0x0fb000f0, 0x01000090, emulate_rd12rn16rm0_rwflags_nopc, | ||
523 | REGS(NOPC, NOPC, 0, 0, NOPC)), | ||
524 | |||
525 | /* LDREX/STREX{,D,B,H} cccc 0001 1xxx xxxx xxxx xxxx 1001 xxxx */ | ||
526 | /* And unallocated instructions... */ | ||
527 | DECODE_END | ||
528 | }; | ||
529 | |||
530 | static const union decode_item arm_cccc_000x_____1xx1_table[] = { | ||
531 | /* Extra load/store instructions */ | ||
532 | |||
533 | /* STRHT cccc 0000 xx10 xxxx xxxx xxxx 1011 xxxx */ | ||
534 | /* ??? cccc 0000 xx10 xxxx xxxx xxxx 11x1 xxxx */ | ||
535 | /* LDRHT cccc 0000 xx11 xxxx xxxx xxxx 1011 xxxx */ | ||
536 | /* LDRSBT cccc 0000 xx11 xxxx xxxx xxxx 1101 xxxx */ | ||
537 | /* LDRSHT cccc 0000 xx11 xxxx xxxx xxxx 1111 xxxx */ | ||
538 | DECODE_REJECT (0x0f200090, 0x00200090), | ||
539 | |||
540 | /* LDRD/STRD lr,pc,{... cccc 000x x0x0 xxxx 111x xxxx 1101 xxxx */ | ||
541 | DECODE_REJECT (0x0e10e0d0, 0x0000e0d0), | ||
542 | |||
543 | /* LDRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1101 xxxx */ | ||
544 | /* STRD (register) cccc 000x x0x0 xxxx xxxx xxxx 1111 xxxx */ | ||
545 | DECODE_EMULATEX (0x0e5000d0, 0x000000d0, emulate_ldrdstrd, | ||
546 | REGS(NOPCWB, NOPCX, 0, 0, NOPC)), | ||
547 | |||
548 | /* LDRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1101 xxxx */ | ||
549 | /* STRD (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1111 xxxx */ | ||
550 | DECODE_EMULATEX (0x0e5000d0, 0x004000d0, emulate_ldrdstrd, | ||
551 | REGS(NOPCWB, NOPCX, 0, 0, 0)), | ||
552 | |||
553 | /* STRH (register) cccc 000x x0x0 xxxx xxxx xxxx 1011 xxxx */ | ||
554 | DECODE_EMULATEX (0x0e5000f0, 0x000000b0, emulate_str, | ||
555 | REGS(NOPCWB, NOPC, 0, 0, NOPC)), | ||
556 | |||
557 | /* LDRH (register) cccc 000x x0x1 xxxx xxxx xxxx 1011 xxxx */ | ||
558 | /* LDRSB (register) cccc 000x x0x1 xxxx xxxx xxxx 1101 xxxx */ | ||
559 | /* LDRSH (register) cccc 000x x0x1 xxxx xxxx xxxx 1111 xxxx */ | ||
560 | DECODE_EMULATEX (0x0e500090, 0x00100090, emulate_ldr, | ||
561 | REGS(NOPCWB, NOPC, 0, 0, NOPC)), | ||
562 | |||
563 | /* STRH (immediate) cccc 000x x1x0 xxxx xxxx xxxx 1011 xxxx */ | ||
564 | DECODE_EMULATEX (0x0e5000f0, 0x004000b0, emulate_str, | ||
565 | REGS(NOPCWB, NOPC, 0, 0, 0)), | ||
566 | |||
567 | /* LDRH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1011 xxxx */ | ||
568 | /* LDRSB (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1101 xxxx */ | ||
569 | /* LDRSH (immediate) cccc 000x x1x1 xxxx xxxx xxxx 1111 xxxx */ | ||
570 | DECODE_EMULATEX (0x0e500090, 0x00500090, emulate_ldr, | ||
571 | REGS(NOPCWB, NOPC, 0, 0, 0)), | ||
572 | |||
573 | DECODE_END | ||
574 | }; | ||
575 | |||
576 | static const union decode_item arm_cccc_000x_table[] = { | ||
577 | /* Data-processing (register) */ | ||
578 | |||
579 | /* <op>S PC, ... cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx */ | ||
580 | DECODE_REJECT (0x0e10f000, 0x0010f000), | ||
581 | |||
582 | /* MOV IP, SP 1110 0001 1010 0000 1100 0000 0000 1101 */ | ||
583 | DECODE_SIMULATE (0xffffffff, 0xe1a0c00d, simulate_mov_ipsp), | ||
584 | |||
585 | /* TST (register) cccc 0001 0001 xxxx xxxx xxxx xxx0 xxxx */ | ||
586 | /* TEQ (register) cccc 0001 0011 xxxx xxxx xxxx xxx0 xxxx */ | ||
587 | /* CMP (register) cccc 0001 0101 xxxx xxxx xxxx xxx0 xxxx */ | ||
588 | /* CMN (register) cccc 0001 0111 xxxx xxxx xxxx xxx0 xxxx */ | ||
589 | DECODE_EMULATEX (0x0f900010, 0x01100000, emulate_rd12rn16rm0rs8_rwflags, | ||
590 | REGS(ANY, 0, 0, 0, ANY)), | ||
591 | |||
592 | /* MOV (register) cccc 0001 101x xxxx xxxx xxxx xxx0 xxxx */ | ||
593 | /* MVN (register) cccc 0001 111x xxxx xxxx xxxx xxx0 xxxx */ | ||
594 | DECODE_EMULATEX (0x0fa00010, 0x01a00000, emulate_rd12rn16rm0rs8_rwflags, | ||
595 | REGS(0, ANY, 0, 0, ANY)), | ||
596 | |||
597 | /* AND (register) cccc 0000 000x xxxx xxxx xxxx xxx0 xxxx */ | ||
598 | /* EOR (register) cccc 0000 001x xxxx xxxx xxxx xxx0 xxxx */ | ||
599 | /* SUB (register) cccc 0000 010x xxxx xxxx xxxx xxx0 xxxx */ | ||
600 | /* RSB (register) cccc 0000 011x xxxx xxxx xxxx xxx0 xxxx */ | ||
601 | /* ADD (register) cccc 0000 100x xxxx xxxx xxxx xxx0 xxxx */ | ||
602 | /* ADC (register) cccc 0000 101x xxxx xxxx xxxx xxx0 xxxx */ | ||
603 | /* SBC (register) cccc 0000 110x xxxx xxxx xxxx xxx0 xxxx */ | ||
604 | /* RSC (register) cccc 0000 111x xxxx xxxx xxxx xxx0 xxxx */ | ||
605 | /* ORR (register) cccc 0001 100x xxxx xxxx xxxx xxx0 xxxx */ | ||
606 | /* BIC (register) cccc 0001 110x xxxx xxxx xxxx xxx0 xxxx */ | ||
607 | DECODE_EMULATEX (0x0e000010, 0x00000000, emulate_rd12rn16rm0rs8_rwflags, | ||
608 | REGS(ANY, ANY, 0, 0, ANY)), | ||
609 | |||
610 | /* TST (reg-shift reg) cccc 0001 0001 xxxx xxxx xxxx 0xx1 xxxx */ | ||
611 | /* TEQ (reg-shift reg) cccc 0001 0011 xxxx xxxx xxxx 0xx1 xxxx */ | ||
612 | /* CMP (reg-shift reg) cccc 0001 0101 xxxx xxxx xxxx 0xx1 xxxx */ | ||
613 | /* CMN (reg-shift reg) cccc 0001 0111 xxxx xxxx xxxx 0xx1 xxxx */ | ||
614 | DECODE_EMULATEX (0x0f900090, 0x01100010, emulate_rd12rn16rm0rs8_rwflags, | ||
615 | REGS(ANY, 0, NOPC, 0, ANY)), | ||
616 | |||
617 | /* MOV (reg-shift reg) cccc 0001 101x xxxx xxxx xxxx 0xx1 xxxx */ | ||
618 | /* MVN (reg-shift reg) cccc 0001 111x xxxx xxxx xxxx 0xx1 xxxx */ | ||
619 | DECODE_EMULATEX (0x0fa00090, 0x01a00010, emulate_rd12rn16rm0rs8_rwflags, | ||
620 | REGS(0, ANY, NOPC, 0, ANY)), | ||
621 | |||
622 | /* AND (reg-shift reg) cccc 0000 000x xxxx xxxx xxxx 0xx1 xxxx */ | ||
623 | /* EOR (reg-shift reg) cccc 0000 001x xxxx xxxx xxxx 0xx1 xxxx */ | ||
624 | /* SUB (reg-shift reg) cccc 0000 010x xxxx xxxx xxxx 0xx1 xxxx */ | ||
625 | /* RSB (reg-shift reg) cccc 0000 011x xxxx xxxx xxxx 0xx1 xxxx */ | ||
626 | /* ADD (reg-shift reg) cccc 0000 100x xxxx xxxx xxxx 0xx1 xxxx */ | ||
627 | /* ADC (reg-shift reg) cccc 0000 101x xxxx xxxx xxxx 0xx1 xxxx */ | ||
628 | /* SBC (reg-shift reg) cccc 0000 110x xxxx xxxx xxxx 0xx1 xxxx */ | ||
629 | /* RSC (reg-shift reg) cccc 0000 111x xxxx xxxx xxxx 0xx1 xxxx */ | ||
630 | /* ORR (reg-shift reg) cccc 0001 100x xxxx xxxx xxxx 0xx1 xxxx */ | ||
631 | /* BIC (reg-shift reg) cccc 0001 110x xxxx xxxx xxxx 0xx1 xxxx */ | ||
632 | DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, | ||
633 | REGS(ANY, ANY, NOPC, 0, ANY)), | ||
634 | |||
635 | DECODE_END | ||
636 | }; | ||
637 | |||
638 | static const union decode_item arm_cccc_001x_table[] = { | ||
639 | /* Data-processing (immediate) */ | ||
640 | |||
641 | /* MOVW cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ | ||
642 | /* MOVT cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
643 | DECODE_EMULATEX (0x0fb00000, 0x03000000, emulate_rd12rm0_noflags_nopc, | ||
644 | REGS(0, NOPC, 0, 0, 0)), | ||
645 | |||
646 | /* YIELD cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ | ||
647 | DECODE_OR (0x0fff00ff, 0x03200001), | ||
648 | /* SEV cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ | ||
649 | DECODE_EMULATE (0x0fff00ff, 0x03200004, kprobe_emulate_none), | ||
650 | /* NOP cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ | ||
651 | /* WFE cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ | ||
652 | /* WFI cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ | ||
653 | DECODE_SIMULATE (0x0fff00fc, 0x03200000, kprobe_simulate_nop), | ||
654 | /* DBG cccc 0011 0010 0000 xxxx xxxx ffff xxxx */ | ||
655 | /* unallocated hints cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ | ||
656 | /* MSR (immediate) cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx */ | ||
657 | DECODE_REJECT (0x0fb00000, 0x03200000), | ||
658 | |||
659 | /* <op>S PC, ... cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx */ | ||
660 | DECODE_REJECT (0x0e10f000, 0x0210f000), | ||
661 | |||
662 | /* TST (immediate) cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx */ | ||
663 | /* TEQ (immediate) cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx */ | ||
664 | /* CMP (immediate) cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
665 | /* CMN (immediate) cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx */ | ||
666 | DECODE_EMULATEX (0x0f900000, 0x03100000, emulate_rd12rn16rm0rs8_rwflags, | ||
667 | REGS(ANY, 0, 0, 0, 0)), | ||
668 | |||
669 | /* MOV (immediate) cccc 0011 101x xxxx xxxx xxxx xxxx xxxx */ | ||
670 | /* MVN (immediate) cccc 0011 111x xxxx xxxx xxxx xxxx xxxx */ | ||
671 | DECODE_EMULATEX (0x0fa00000, 0x03a00000, emulate_rd12rn16rm0rs8_rwflags, | ||
672 | REGS(0, ANY, 0, 0, 0)), | ||
673 | |||
674 | /* AND (immediate) cccc 0010 000x xxxx xxxx xxxx xxxx xxxx */ | ||
675 | /* EOR (immediate) cccc 0010 001x xxxx xxxx xxxx xxxx xxxx */ | ||
676 | /* SUB (immediate) cccc 0010 010x xxxx xxxx xxxx xxxx xxxx */ | ||
677 | /* RSB (immediate) cccc 0010 011x xxxx xxxx xxxx xxxx xxxx */ | ||
678 | /* ADD (immediate) cccc 0010 100x xxxx xxxx xxxx xxxx xxxx */ | ||
679 | /* ADC (immediate) cccc 0010 101x xxxx xxxx xxxx xxxx xxxx */ | ||
680 | /* SBC (immediate) cccc 0010 110x xxxx xxxx xxxx xxxx xxxx */ | ||
681 | /* RSC (immediate) cccc 0010 111x xxxx xxxx xxxx xxxx xxxx */ | ||
682 | /* ORR (immediate) cccc 0011 100x xxxx xxxx xxxx xxxx xxxx */ | ||
683 | /* BIC (immediate) cccc 0011 110x xxxx xxxx xxxx xxxx xxxx */ | ||
684 | DECODE_EMULATEX (0x0e000000, 0x02000000, emulate_rd12rn16rm0rs8_rwflags, | ||
685 | REGS(ANY, ANY, 0, 0, 0)), | ||
686 | |||
687 | DECODE_END | ||
688 | }; | ||
689 | |||
690 | static const union decode_item arm_cccc_0110_____xxx1_table[] = { | ||
691 | /* Media instructions */ | ||
692 | |||
693 | /* SEL cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx */ | ||
694 | DECODE_EMULATEX (0x0ff000f0, 0x068000b0, emulate_rd12rn16rm0_rwflags_nopc, | ||
695 | REGS(NOPC, NOPC, 0, 0, NOPC)), | ||
696 | |||
697 | /* SSAT cccc 0110 101x xxxx xxxx xxxx xx01 xxxx */ | ||
698 | /* USAT cccc 0110 111x xxxx xxxx xxxx xx01 xxxx */ | ||
699 | DECODE_OR(0x0fa00030, 0x06a00010), | ||
700 | /* SSAT16 cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx */ | ||
701 | /* USAT16 cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx */ | ||
702 | DECODE_EMULATEX (0x0fb000f0, 0x06a00030, emulate_rd12rn16rm0_rwflags_nopc, | ||
703 | REGS(0, NOPC, 0, 0, NOPC)), | ||
704 | |||
705 | /* REV cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ | ||
706 | /* REV16 cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ | ||
707 | /* RBIT cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ | ||
708 | /* REVSH cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ | ||
709 | DECODE_EMULATEX (0x0fb00070, 0x06b00030, emulate_rd12rm0_noflags_nopc, | ||
710 | REGS(0, NOPC, 0, 0, NOPC)), | ||
711 | |||
712 | /* ??? cccc 0110 0x00 xxxx xxxx xxxx xxx1 xxxx */ | ||
713 | DECODE_REJECT (0x0fb00010, 0x06000010), | ||
714 | /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1011 xxxx */ | ||
715 | DECODE_REJECT (0x0f8000f0, 0x060000b0), | ||
716 | /* ??? cccc 0110 0xxx xxxx xxxx xxxx 1101 xxxx */ | ||
717 | DECODE_REJECT (0x0f8000f0, 0x060000d0), | ||
718 | /* SADD16 cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx */ | ||
719 | /* SADDSUBX cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx */ | ||
720 | /* SSUBADDX cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx */ | ||
721 | /* SSUB16 cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx */ | ||
722 | /* SADD8 cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx */ | ||
723 | /* SSUB8 cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx */ | ||
724 | /* QADD16 cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx */ | ||
725 | /* QADDSUBX cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx */ | ||
726 | /* QSUBADDX cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx */ | ||
727 | /* QSUB16 cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx */ | ||
728 | /* QADD8 cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx */ | ||
729 | /* QSUB8 cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx */ | ||
730 | /* SHADD16 cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx */ | ||
731 | /* SHADDSUBX cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx */ | ||
732 | /* SHSUBADDX cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx */ | ||
733 | /* SHSUB16 cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx */ | ||
734 | /* SHADD8 cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx */ | ||
735 | /* SHSUB8 cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx */ | ||
736 | /* UADD16 cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx */ | ||
737 | /* UADDSUBX cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx */ | ||
738 | /* USUBADDX cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx */ | ||
739 | /* USUB16 cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx */ | ||
740 | /* UADD8 cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx */ | ||
741 | /* USUB8 cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx */ | ||
742 | /* UQADD16 cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx */ | ||
743 | /* UQADDSUBX cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx */ | ||
744 | /* UQSUBADDX cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx */ | ||
745 | /* UQSUB16 cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx */ | ||
746 | /* UQADD8 cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx */ | ||
747 | /* UQSUB8 cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx */ | ||
748 | /* UHADD16 cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx */ | ||
749 | /* UHADDSUBX cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx */ | ||
750 | /* UHSUBADDX cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx */ | ||
751 | /* UHSUB16 cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx */ | ||
752 | /* UHADD8 cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx */ | ||
753 | /* UHSUB8 cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx */ | ||
754 | DECODE_EMULATEX (0x0f800010, 0x06000010, emulate_rd12rn16rm0_rwflags_nopc, | ||
755 | REGS(NOPC, NOPC, 0, 0, NOPC)), | ||
756 | |||
757 | /* PKHBT cccc 0110 1000 xxxx xxxx xxxx x001 xxxx */ | ||
758 | /* PKHTB cccc 0110 1000 xxxx xxxx xxxx x101 xxxx */ | ||
759 | DECODE_EMULATEX (0x0ff00030, 0x06800010, emulate_rd12rn16rm0_rwflags_nopc, | ||
760 | REGS(NOPC, NOPC, 0, 0, NOPC)), | ||
761 | |||
762 | /* ??? cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx */ | ||
763 | /* ??? cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx */ | ||
764 | DECODE_REJECT (0x0fb000f0, 0x06900070), | ||
765 | |||
766 | /* SXTB16 cccc 0110 1000 1111 xxxx xxxx 0111 xxxx */ | ||
767 | /* SXTB cccc 0110 1010 1111 xxxx xxxx 0111 xxxx */ | ||
768 | /* SXTH cccc 0110 1011 1111 xxxx xxxx 0111 xxxx */ | ||
769 | /* UXTB16 cccc 0110 1100 1111 xxxx xxxx 0111 xxxx */ | ||
770 | /* UXTB cccc 0110 1110 1111 xxxx xxxx 0111 xxxx */ | ||
771 | /* UXTH cccc 0110 1111 1111 xxxx xxxx 0111 xxxx */ | ||
772 | DECODE_EMULATEX (0x0f8f00f0, 0x068f0070, emulate_rd12rm0_noflags_nopc, | ||
773 | REGS(0, NOPC, 0, 0, NOPC)), | ||
774 | |||
775 | /* SXTAB16 cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx */ | ||
776 | /* SXTAB cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx */ | ||
777 | /* SXTAH cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx */ | ||
778 | /* UXTAB16 cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx */ | ||
779 | /* UXTAB cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx */ | ||
780 | /* UXTAH cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx */ | ||
781 | DECODE_EMULATEX (0x0f8000f0, 0x06800070, emulate_rd12rn16rm0_rwflags_nopc, | ||
782 | REGS(NOPCX, NOPC, 0, 0, NOPC)), | ||
783 | |||
784 | DECODE_END | ||
785 | }; | ||
786 | |||
787 | static const union decode_item arm_cccc_0111_____xxx1_table[] = { | ||
788 | /* Media instructions */ | ||
789 | |||
790 | /* UNDEFINED cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ | ||
791 | DECODE_REJECT (0x0ff000f0, 0x07f000f0), | ||
792 | |||
793 | /* SMLALD cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ | ||
794 | /* SMLSLD cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ | ||
795 | DECODE_EMULATEX (0x0ff00090, 0x07400010, emulate_rdlo12rdhi16rn0rm8_rwflags_nopc, | ||
796 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
797 | |||
798 | /* SMUAD cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx */ | ||
799 | /* SMUSD cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx */ | ||
800 | DECODE_OR (0x0ff0f090, 0x0700f010), | ||
801 | /* SMMUL cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx */ | ||
802 | DECODE_OR (0x0ff0f0d0, 0x0750f010), | ||
803 | /* USAD8 cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx */ | ||
804 | DECODE_EMULATEX (0x0ff0f0f0, 0x0780f010, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
805 | REGS(NOPC, 0, NOPC, 0, NOPC)), | ||
806 | |||
807 | /* SMLAD cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx */ | ||
808 | /* SMLSD cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx */ | ||
809 | DECODE_OR (0x0ff00090, 0x07000010), | ||
810 | /* SMMLA cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx */ | ||
811 | DECODE_OR (0x0ff000d0, 0x07500010), | ||
812 | /* USADA8 cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx */ | ||
813 | DECODE_EMULATEX (0x0ff000f0, 0x07800010, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
814 | REGS(NOPC, NOPCX, NOPC, 0, NOPC)), | ||
815 | |||
816 | /* SMMLS cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx */ | ||
817 | DECODE_EMULATEX (0x0ff000d0, 0x075000d0, emulate_rd16rn12rm0rs8_rwflags_nopc, | ||
818 | REGS(NOPC, NOPC, NOPC, 0, NOPC)), | ||
819 | |||
820 | /* SBFX cccc 0111 101x xxxx xxxx xxxx x101 xxxx */ | ||
821 | /* UBFX cccc 0111 111x xxxx xxxx xxxx x101 xxxx */ | ||
822 | DECODE_EMULATEX (0x0fa00070, 0x07a00050, emulate_rd12rm0_noflags_nopc, | ||
823 | REGS(0, NOPC, 0, 0, NOPC)), | ||
824 | |||
825 | /* BFC cccc 0111 110x xxxx xxxx xxxx x001 1111 */ | ||
826 | DECODE_EMULATEX (0x0fe0007f, 0x07c0001f, emulate_rd12rm0_noflags_nopc, | ||
827 | REGS(0, NOPC, 0, 0, 0)), | ||
828 | |||
829 | /* BFI cccc 0111 110x xxxx xxxx xxxx x001 xxxx */ | ||
830 | DECODE_EMULATEX (0x0fe00070, 0x07c00010, emulate_rd12rm0_noflags_nopc, | ||
831 | REGS(0, NOPC, 0, 0, NOPCX)), | ||
832 | |||
833 | DECODE_END | ||
834 | }; | ||
835 | |||
836 | static const union decode_item arm_cccc_01xx_table[] = { | ||
837 | /* Load/store word and unsigned byte */ | ||
838 | |||
839 | /* LDRB/STRB pc,[...] cccc 01xx x0xx xxxx xxxx xxxx xxxx xxxx */ | ||
840 | DECODE_REJECT (0x0c40f000, 0x0440f000), | ||
841 | |||
842 | /* STRT cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ | ||
843 | /* LDRT cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ | ||
844 | /* STRBT cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ | ||
845 | /* LDRBT cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ | ||
846 | DECODE_REJECT (0x0d200000, 0x04200000), | ||
847 | |||
848 | /* STR (immediate) cccc 010x x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
849 | /* STRB (immediate) cccc 010x x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
850 | DECODE_EMULATEX (0x0e100000, 0x04000000, emulate_str, | ||
851 | REGS(NOPCWB, ANY, 0, 0, 0)), | ||
852 | |||
853 | /* LDR (immediate) cccc 010x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
854 | /* LDRB (immediate) cccc 010x x1x1 xxxx xxxx xxxx xxxx xxxx */ | ||
855 | DECODE_EMULATEX (0x0e100000, 0x04100000, emulate_ldr, | ||
856 | REGS(NOPCWB, ANY, 0, 0, 0)), | ||
857 | |||
858 | /* STR (register) cccc 011x x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
859 | /* STRB (register) cccc 011x x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
860 | DECODE_EMULATEX (0x0e100000, 0x06000000, emulate_str, | ||
861 | REGS(NOPCWB, ANY, 0, 0, NOPC)), | ||
862 | |||
863 | /* LDR (register) cccc 011x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
864 | /* LDRB (register) cccc 011x x1x1 xxxx xxxx xxxx xxxx xxxx */ | ||
865 | DECODE_EMULATEX (0x0e100000, 0x06100000, emulate_ldr, | ||
866 | REGS(NOPCWB, ANY, 0, 0, NOPC)), | ||
867 | |||
868 | DECODE_END | ||
869 | }; | ||
870 | |||
871 | static const union decode_item arm_cccc_100x_table[] = { | ||
872 | /* Block data transfer instructions */ | ||
873 | |||
874 | /* LDM cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
875 | /* STM cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
876 | DECODE_CUSTOM (0x0e400000, 0x08000000, kprobe_decode_ldmstm), | ||
877 | |||
878 | /* STM (user registers) cccc 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
879 | /* LDM (user registers) cccc 100x x1x1 xxxx 0xxx xxxx xxxx xxxx */ | ||
880 | /* LDM (exception ret) cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ | ||
881 | DECODE_END | ||
882 | }; | ||
883 | |||
884 | const union decode_item kprobe_decode_arm_table[] = { | ||
885 | /* | ||
886 | * Unconditional instructions | ||
887 | * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx | ||
888 | */ | ||
889 | DECODE_TABLE (0xf0000000, 0xf0000000, arm_1111_table), | ||
890 | |||
891 | /* | ||
892 | * Miscellaneous instructions | ||
893 | * cccc 0001 0xx0 xxxx xxxx xxxx 0xxx xxxx | ||
894 | */ | ||
895 | DECODE_TABLE (0x0f900080, 0x01000000, arm_cccc_0001_0xx0____0xxx_table), | ||
896 | |||
897 | /* | ||
898 | * Halfword multiply and multiply-accumulate | ||
899 | * cccc 0001 0xx0 xxxx xxxx xxxx 1xx0 xxxx | ||
900 | */ | ||
901 | DECODE_TABLE (0x0f900090, 0x01000080, arm_cccc_0001_0xx0____1xx0_table), | ||
902 | |||
903 | /* | ||
904 | * Multiply and multiply-accumulate | ||
905 | * cccc 0000 xxxx xxxx xxxx xxxx 1001 xxxx | ||
906 | */ | ||
907 | DECODE_TABLE (0x0f0000f0, 0x00000090, arm_cccc_0000_____1001_table), | ||
908 | |||
909 | /* | ||
910 | * Synchronization primitives | ||
911 | * cccc 0001 xxxx xxxx xxxx xxxx 1001 xxxx | ||
912 | */ | ||
913 | DECODE_TABLE (0x0f0000f0, 0x01000090, arm_cccc_0001_____1001_table), | ||
914 | |||
915 | /* | ||
916 | * Extra load/store instructions | ||
917 | * cccc 000x xxxx xxxx xxxx xxxx 1xx1 xxxx | ||
918 | */ | ||
919 | DECODE_TABLE (0x0e000090, 0x00000090, arm_cccc_000x_____1xx1_table), | ||
920 | |||
921 | /* | ||
922 | * Data-processing (register) | ||
923 | * cccc 000x xxxx xxxx xxxx xxxx xxx0 xxxx | ||
924 | * Data-processing (register-shifted register) | ||
925 | * cccc 000x xxxx xxxx xxxx xxxx 0xx1 xxxx | ||
926 | */ | ||
927 | DECODE_TABLE (0x0e000000, 0x00000000, arm_cccc_000x_table), | ||
928 | |||
929 | /* | ||
930 | * Data-processing (immediate) | ||
931 | * cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx | ||
932 | */ | ||
933 | DECODE_TABLE (0x0e000000, 0x02000000, arm_cccc_001x_table), | ||
934 | |||
935 | /* | ||
936 | * Media instructions | ||
937 | * cccc 011x xxxx xxxx xxxx xxxx xxx1 xxxx | ||
938 | */ | ||
939 | DECODE_TABLE (0x0f000010, 0x06000010, arm_cccc_0110_____xxx1_table), | ||
940 | DECODE_TABLE (0x0f000010, 0x07000010, arm_cccc_0111_____xxx1_table), | ||
941 | |||
942 | /* | ||
943 | * Load/store word and unsigned byte | ||
944 | * cccc 01xx xxxx xxxx xxxx xxxx xxxx xxxx | ||
945 | */ | ||
946 | DECODE_TABLE (0x0c000000, 0x04000000, arm_cccc_01xx_table), | ||
947 | |||
948 | /* | ||
949 | * Block data transfer instructions | ||
950 | * cccc 100x xxxx xxxx xxxx xxxx xxxx xxxx | ||
951 | */ | ||
952 | DECODE_TABLE (0x0e000000, 0x08000000, arm_cccc_100x_table), | ||
953 | |||
954 | /* B cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
955 | /* BL cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
956 | DECODE_SIMULATE (0x0e000000, 0x0a000000, simulate_bbl), | ||
957 | |||
958 | /* | ||
959 | * Supervisor Call, and coprocessor instructions | ||
960 | */ | ||
961 | |||
962 | /* MCRR cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
963 | /* MRRC cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
964 | /* LDC cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
965 | /* STC cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
966 | /* CDP cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
967 | /* MCR cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
968 | /* MRC cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
969 | /* SVC cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
970 | DECODE_REJECT (0x0c000000, 0x0c000000), | ||
971 | |||
972 | DECODE_END | ||
973 | }; | ||
974 | |||
975 | static void __kprobes arm_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
976 | { | ||
977 | regs->ARM_pc += 4; | ||
978 | p->ainsn.insn_handler(p, regs); | ||
979 | } | ||
980 | |||
981 | /* Return: | ||
982 | * INSN_REJECTED If instruction is one not allowed to kprobe, | ||
983 | * INSN_GOOD If instruction is supported and uses instruction slot, | ||
984 | * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. | ||
985 | * | ||
986 | * For instructions we don't want to kprobe (INSN_REJECTED return result): | ||
987 | * These are generally ones that modify the processor state making | ||
988 | * them "hard" to simulate such as switches processor modes or | ||
989 | * make accesses in alternate modes. Any of these could be simulated | ||
990 | * if the work was put into it, but low return considering they | ||
991 | * should also be very rare. | ||
992 | */ | ||
993 | enum kprobe_insn __kprobes | ||
994 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
995 | { | ||
996 | asi->insn_singlestep = arm_singlestep; | ||
997 | asi->insn_check_cc = kprobe_condition_checks[insn>>28]; | ||
998 | return kprobe_decode_insn(insn, asi, kprobe_decode_arm_table, false); | ||
999 | } | ||
diff --git a/arch/arm/kernel/kprobes-common.c b/arch/arm/kernel/kprobes-common.c new file mode 100644 index 000000000000..a5394fb4e4e0 --- /dev/null +++ b/arch/arm/kernel/kprobes-common.c | |||
@@ -0,0 +1,577 @@ | |||
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 | #ifndef find_str_pc_offset | ||
21 | |||
22 | /* | ||
23 | * For STR and STM instructions, an ARM core may choose to use either | ||
24 | * a +8 or a +12 displacement from the current instruction's address. | ||
25 | * Whichever value is chosen for a given core, it must be the same for | ||
26 | * both instructions and may not change. This function measures it. | ||
27 | */ | ||
28 | |||
29 | int str_pc_offset; | ||
30 | |||
31 | void __init find_str_pc_offset(void) | ||
32 | { | ||
33 | int addr, scratch, ret; | ||
34 | |||
35 | __asm__ ( | ||
36 | "sub %[ret], pc, #4 \n\t" | ||
37 | "str pc, %[addr] \n\t" | ||
38 | "ldr %[scr], %[addr] \n\t" | ||
39 | "sub %[ret], %[scr], %[ret] \n\t" | ||
40 | : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); | ||
41 | |||
42 | str_pc_offset = ret; | ||
43 | } | ||
44 | |||
45 | #endif /* !find_str_pc_offset */ | ||
46 | |||
47 | |||
48 | #ifndef test_load_write_pc_interworking | ||
49 | |||
50 | bool load_write_pc_interworks; | ||
51 | |||
52 | void __init test_load_write_pc_interworking(void) | ||
53 | { | ||
54 | int arch = cpu_architecture(); | ||
55 | BUG_ON(arch == CPU_ARCH_UNKNOWN); | ||
56 | load_write_pc_interworks = arch >= CPU_ARCH_ARMv5T; | ||
57 | } | ||
58 | |||
59 | #endif /* !test_load_write_pc_interworking */ | ||
60 | |||
61 | |||
62 | #ifndef test_alu_write_pc_interworking | ||
63 | |||
64 | bool alu_write_pc_interworks; | ||
65 | |||
66 | void __init test_alu_write_pc_interworking(void) | ||
67 | { | ||
68 | int arch = cpu_architecture(); | ||
69 | BUG_ON(arch == CPU_ARCH_UNKNOWN); | ||
70 | alu_write_pc_interworks = arch >= CPU_ARCH_ARMv7; | ||
71 | } | ||
72 | |||
73 | #endif /* !test_alu_write_pc_interworking */ | ||
74 | |||
75 | |||
76 | void __init arm_kprobe_decode_init(void) | ||
77 | { | ||
78 | find_str_pc_offset(); | ||
79 | test_load_write_pc_interworking(); | ||
80 | test_alu_write_pc_interworking(); | ||
81 | } | ||
82 | |||
83 | |||
84 | static unsigned long __kprobes __check_eq(unsigned long cpsr) | ||
85 | { | ||
86 | return cpsr & PSR_Z_BIT; | ||
87 | } | ||
88 | |||
89 | static unsigned long __kprobes __check_ne(unsigned long cpsr) | ||
90 | { | ||
91 | return (~cpsr) & PSR_Z_BIT; | ||
92 | } | ||
93 | |||
94 | static unsigned long __kprobes __check_cs(unsigned long cpsr) | ||
95 | { | ||
96 | return cpsr & PSR_C_BIT; | ||
97 | } | ||
98 | |||
99 | static unsigned long __kprobes __check_cc(unsigned long cpsr) | ||
100 | { | ||
101 | return (~cpsr) & PSR_C_BIT; | ||
102 | } | ||
103 | |||
104 | static unsigned long __kprobes __check_mi(unsigned long cpsr) | ||
105 | { | ||
106 | return cpsr & PSR_N_BIT; | ||
107 | } | ||
108 | |||
109 | static unsigned long __kprobes __check_pl(unsigned long cpsr) | ||
110 | { | ||
111 | return (~cpsr) & PSR_N_BIT; | ||
112 | } | ||
113 | |||
114 | static unsigned long __kprobes __check_vs(unsigned long cpsr) | ||
115 | { | ||
116 | return cpsr & PSR_V_BIT; | ||
117 | } | ||
118 | |||
119 | static unsigned long __kprobes __check_vc(unsigned long cpsr) | ||
120 | { | ||
121 | return (~cpsr) & PSR_V_BIT; | ||
122 | } | ||
123 | |||
124 | static unsigned long __kprobes __check_hi(unsigned long cpsr) | ||
125 | { | ||
126 | cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ | ||
127 | return cpsr & PSR_C_BIT; | ||
128 | } | ||
129 | |||
130 | static unsigned long __kprobes __check_ls(unsigned long cpsr) | ||
131 | { | ||
132 | cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ | ||
133 | return (~cpsr) & PSR_C_BIT; | ||
134 | } | ||
135 | |||
136 | static unsigned long __kprobes __check_ge(unsigned long cpsr) | ||
137 | { | ||
138 | cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
139 | return (~cpsr) & PSR_N_BIT; | ||
140 | } | ||
141 | |||
142 | static unsigned long __kprobes __check_lt(unsigned long cpsr) | ||
143 | { | ||
144 | cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
145 | return cpsr & PSR_N_BIT; | ||
146 | } | ||
147 | |||
148 | static unsigned long __kprobes __check_gt(unsigned long cpsr) | ||
149 | { | ||
150 | unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
151 | temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ | ||
152 | return (~temp) & PSR_N_BIT; | ||
153 | } | ||
154 | |||
155 | static unsigned long __kprobes __check_le(unsigned long cpsr) | ||
156 | { | ||
157 | unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
158 | temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ | ||
159 | return temp & PSR_N_BIT; | ||
160 | } | ||
161 | |||
162 | static unsigned long __kprobes __check_al(unsigned long cpsr) | ||
163 | { | ||
164 | return true; | ||
165 | } | ||
166 | |||
167 | kprobe_check_cc * const kprobe_condition_checks[16] = { | ||
168 | &__check_eq, &__check_ne, &__check_cs, &__check_cc, | ||
169 | &__check_mi, &__check_pl, &__check_vs, &__check_vc, | ||
170 | &__check_hi, &__check_ls, &__check_ge, &__check_lt, | ||
171 | &__check_gt, &__check_le, &__check_al, &__check_al | ||
172 | }; | ||
173 | |||
174 | |||
175 | void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs) | ||
176 | { | ||
177 | } | ||
178 | |||
179 | void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs) | ||
180 | { | ||
181 | p->ainsn.insn_fn(); | ||
182 | } | ||
183 | |||
184 | static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) | ||
185 | { | ||
186 | kprobe_opcode_t insn = p->opcode; | ||
187 | int rn = (insn >> 16) & 0xf; | ||
188 | int lbit = insn & (1 << 20); | ||
189 | int wbit = insn & (1 << 21); | ||
190 | int ubit = insn & (1 << 23); | ||
191 | int pbit = insn & (1 << 24); | ||
192 | long *addr = (long *)regs->uregs[rn]; | ||
193 | int reg_bit_vector; | ||
194 | int reg_count; | ||
195 | |||
196 | reg_count = 0; | ||
197 | reg_bit_vector = insn & 0xffff; | ||
198 | while (reg_bit_vector) { | ||
199 | reg_bit_vector &= (reg_bit_vector - 1); | ||
200 | ++reg_count; | ||
201 | } | ||
202 | |||
203 | if (!ubit) | ||
204 | addr -= reg_count; | ||
205 | addr += (!pbit == !ubit); | ||
206 | |||
207 | reg_bit_vector = insn & 0xffff; | ||
208 | while (reg_bit_vector) { | ||
209 | int reg = __ffs(reg_bit_vector); | ||
210 | reg_bit_vector &= (reg_bit_vector - 1); | ||
211 | if (lbit) | ||
212 | regs->uregs[reg] = *addr++; | ||
213 | else | ||
214 | *addr++ = regs->uregs[reg]; | ||
215 | } | ||
216 | |||
217 | if (wbit) { | ||
218 | if (!ubit) | ||
219 | addr -= reg_count; | ||
220 | addr -= (!pbit == !ubit); | ||
221 | regs->uregs[rn] = (long)addr; | ||
222 | } | ||
223 | } | ||
224 | |||
225 | static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) | ||
226 | { | ||
227 | regs->ARM_pc = (long)p->addr + str_pc_offset; | ||
228 | simulate_ldm1stm1(p, regs); | ||
229 | regs->ARM_pc = (long)p->addr + 4; | ||
230 | } | ||
231 | |||
232 | static void __kprobes simulate_ldm1_pc(struct kprobe *p, struct pt_regs *regs) | ||
233 | { | ||
234 | simulate_ldm1stm1(p, regs); | ||
235 | load_write_pc(regs->ARM_pc, regs); | ||
236 | } | ||
237 | |||
238 | static void __kprobes | ||
239 | emulate_generic_r0_12_noflags(struct kprobe *p, struct pt_regs *regs) | ||
240 | { | ||
241 | register void *rregs asm("r1") = regs; | ||
242 | register void *rfn asm("lr") = p->ainsn.insn_fn; | ||
243 | |||
244 | __asm__ __volatile__ ( | ||
245 | "stmdb sp!, {%[regs], r11} \n\t" | ||
246 | "ldmia %[regs], {r0-r12} \n\t" | ||
247 | #if __LINUX_ARM_ARCH__ >= 6 | ||
248 | "blx %[fn] \n\t" | ||
249 | #else | ||
250 | "str %[fn], [sp, #-4]! \n\t" | ||
251 | "adr lr, 1f \n\t" | ||
252 | "ldr pc, [sp], #4 \n\t" | ||
253 | "1: \n\t" | ||
254 | #endif | ||
255 | "ldr lr, [sp], #4 \n\t" /* lr = regs */ | ||
256 | "stmia lr, {r0-r12} \n\t" | ||
257 | "ldr r11, [sp], #4 \n\t" | ||
258 | : [regs] "=r" (rregs), [fn] "=r" (rfn) | ||
259 | : "0" (rregs), "1" (rfn) | ||
260 | : "r0", "r2", "r3", "r4", "r5", "r6", "r7", | ||
261 | "r8", "r9", "r10", "r12", "memory", "cc" | ||
262 | ); | ||
263 | } | ||
264 | |||
265 | static void __kprobes | ||
266 | emulate_generic_r2_14_noflags(struct kprobe *p, struct pt_regs *regs) | ||
267 | { | ||
268 | emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+2)); | ||
269 | } | ||
270 | |||
271 | static void __kprobes | ||
272 | emulate_ldm_r3_15(struct kprobe *p, struct pt_regs *regs) | ||
273 | { | ||
274 | emulate_generic_r0_12_noflags(p, (struct pt_regs *)(regs->uregs+3)); | ||
275 | load_write_pc(regs->ARM_pc, regs); | ||
276 | } | ||
277 | |||
278 | enum kprobe_insn __kprobes | ||
279 | kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
280 | { | ||
281 | kprobe_insn_handler_t *handler = 0; | ||
282 | unsigned reglist = insn & 0xffff; | ||
283 | int is_ldm = insn & 0x100000; | ||
284 | int rn = (insn >> 16) & 0xf; | ||
285 | |||
286 | if (rn <= 12 && (reglist & 0xe000) == 0) { | ||
287 | /* Instruction only uses registers in the range R0..R12 */ | ||
288 | handler = emulate_generic_r0_12_noflags; | ||
289 | |||
290 | } else if (rn >= 2 && (reglist & 0x8003) == 0) { | ||
291 | /* Instruction only uses registers in the range R2..R14 */ | ||
292 | rn -= 2; | ||
293 | reglist >>= 2; | ||
294 | handler = emulate_generic_r2_14_noflags; | ||
295 | |||
296 | } else if (rn >= 3 && (reglist & 0x0007) == 0) { | ||
297 | /* Instruction only uses registers in the range R3..R15 */ | ||
298 | if (is_ldm && (reglist & 0x8000)) { | ||
299 | rn -= 3; | ||
300 | reglist >>= 3; | ||
301 | handler = emulate_ldm_r3_15; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | if (handler) { | ||
306 | /* We can emulate the instruction in (possibly) modified form */ | ||
307 | asi->insn[0] = (insn & 0xfff00000) | (rn << 16) | reglist; | ||
308 | asi->insn_handler = handler; | ||
309 | return INSN_GOOD; | ||
310 | } | ||
311 | |||
312 | /* Fallback to slower simulation... */ | ||
313 | if (reglist & 0x8000) | ||
314 | handler = is_ldm ? simulate_ldm1_pc : simulate_stm1_pc; | ||
315 | else | ||
316 | handler = simulate_ldm1stm1; | ||
317 | asi->insn_handler = handler; | ||
318 | return INSN_GOOD_NO_SLOT; | ||
319 | } | ||
320 | |||
321 | |||
322 | /* | ||
323 | * Prepare an instruction slot to receive an instruction for emulating. | ||
324 | * This is done by placing a subroutine return after the location where the | ||
325 | * instruction will be placed. We also modify ARM instructions to be | ||
326 | * unconditional as the condition code will already be checked before any | ||
327 | * emulation handler is called. | ||
328 | */ | ||
329 | static kprobe_opcode_t __kprobes | ||
330 | prepare_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, | ||
331 | bool thumb) | ||
332 | { | ||
333 | #ifdef CONFIG_THUMB2_KERNEL | ||
334 | if (thumb) { | ||
335 | u16 *thumb_insn = (u16 *)asi->insn; | ||
336 | thumb_insn[1] = 0x4770; /* Thumb bx lr */ | ||
337 | thumb_insn[2] = 0x4770; /* Thumb bx lr */ | ||
338 | return insn; | ||
339 | } | ||
340 | asi->insn[1] = 0xe12fff1e; /* ARM bx lr */ | ||
341 | #else | ||
342 | asi->insn[1] = 0xe1a0f00e; /* mov pc, lr */ | ||
343 | #endif | ||
344 | /* Make an ARM instruction unconditional */ | ||
345 | if (insn < 0xe0000000) | ||
346 | insn = (insn | 0xe0000000) & ~0x10000000; | ||
347 | return insn; | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | * Write a (probably modified) instruction into the slot previously prepared by | ||
352 | * prepare_emulated_insn | ||
353 | */ | ||
354 | static void __kprobes | ||
355 | set_emulated_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, | ||
356 | bool thumb) | ||
357 | { | ||
358 | #ifdef CONFIG_THUMB2_KERNEL | ||
359 | if (thumb) { | ||
360 | u16 *ip = (u16 *)asi->insn; | ||
361 | if (is_wide_instruction(insn)) | ||
362 | *ip++ = insn >> 16; | ||
363 | *ip++ = insn; | ||
364 | return; | ||
365 | } | ||
366 | #endif | ||
367 | asi->insn[0] = insn; | ||
368 | } | ||
369 | |||
370 | /* | ||
371 | * When we modify the register numbers encoded in an instruction to be emulated, | ||
372 | * the new values come from this define. For ARM and 32-bit Thumb instructions | ||
373 | * this gives... | ||
374 | * | ||
375 | * bit position 16 12 8 4 0 | ||
376 | * ---------------+---+---+---+---+---+ | ||
377 | * register r2 r0 r1 -- r3 | ||
378 | */ | ||
379 | #define INSN_NEW_BITS 0x00020103 | ||
380 | |||
381 | /* Each nibble has same value as that at INSN_NEW_BITS bit 16 */ | ||
382 | #define INSN_SAMEAS16_BITS 0x22222222 | ||
383 | |||
384 | /* | ||
385 | * Validate and modify each of the registers encoded in an instruction. | ||
386 | * | ||
387 | * Each nibble in regs contains a value from enum decode_reg_type. For each | ||
388 | * non-zero value, the corresponding nibble in pinsn is validated and modified | ||
389 | * according to the type. | ||
390 | */ | ||
391 | static bool __kprobes decode_regs(kprobe_opcode_t* pinsn, u32 regs) | ||
392 | { | ||
393 | kprobe_opcode_t insn = *pinsn; | ||
394 | kprobe_opcode_t mask = 0xf; /* Start at least significant nibble */ | ||
395 | |||
396 | for (; regs != 0; regs >>= 4, mask <<= 4) { | ||
397 | |||
398 | kprobe_opcode_t new_bits = INSN_NEW_BITS; | ||
399 | |||
400 | switch (regs & 0xf) { | ||
401 | |||
402 | case REG_TYPE_NONE: | ||
403 | /* Nibble not a register, skip to next */ | ||
404 | continue; | ||
405 | |||
406 | case REG_TYPE_ANY: | ||
407 | /* Any register is allowed */ | ||
408 | break; | ||
409 | |||
410 | case REG_TYPE_SAMEAS16: | ||
411 | /* Replace register with same as at bit position 16 */ | ||
412 | new_bits = INSN_SAMEAS16_BITS; | ||
413 | break; | ||
414 | |||
415 | case REG_TYPE_SP: | ||
416 | /* Only allow SP (R13) */ | ||
417 | if ((insn ^ 0xdddddddd) & mask) | ||
418 | goto reject; | ||
419 | break; | ||
420 | |||
421 | case REG_TYPE_PC: | ||
422 | /* Only allow PC (R15) */ | ||
423 | if ((insn ^ 0xffffffff) & mask) | ||
424 | goto reject; | ||
425 | break; | ||
426 | |||
427 | case REG_TYPE_NOSP: | ||
428 | /* Reject SP (R13) */ | ||
429 | if (((insn ^ 0xdddddddd) & mask) == 0) | ||
430 | goto reject; | ||
431 | break; | ||
432 | |||
433 | case REG_TYPE_NOSPPC: | ||
434 | case REG_TYPE_NOSPPCX: | ||
435 | /* Reject SP and PC (R13 and R15) */ | ||
436 | if (((insn ^ 0xdddddddd) & 0xdddddddd & mask) == 0) | ||
437 | goto reject; | ||
438 | break; | ||
439 | |||
440 | case REG_TYPE_NOPCWB: | ||
441 | if (!is_writeback(insn)) | ||
442 | break; /* No writeback, so any register is OK */ | ||
443 | /* fall through... */ | ||
444 | case REG_TYPE_NOPC: | ||
445 | case REG_TYPE_NOPCX: | ||
446 | /* Reject PC (R15) */ | ||
447 | if (((insn ^ 0xffffffff) & mask) == 0) | ||
448 | goto reject; | ||
449 | break; | ||
450 | } | ||
451 | |||
452 | /* Replace value of nibble with new register number... */ | ||
453 | insn &= ~mask; | ||
454 | insn |= new_bits & mask; | ||
455 | } | ||
456 | |||
457 | *pinsn = insn; | ||
458 | return true; | ||
459 | |||
460 | reject: | ||
461 | return false; | ||
462 | } | ||
463 | |||
464 | static const int decode_struct_sizes[NUM_DECODE_TYPES] = { | ||
465 | [DECODE_TYPE_TABLE] = sizeof(struct decode_table), | ||
466 | [DECODE_TYPE_CUSTOM] = sizeof(struct decode_custom), | ||
467 | [DECODE_TYPE_SIMULATE] = sizeof(struct decode_simulate), | ||
468 | [DECODE_TYPE_EMULATE] = sizeof(struct decode_emulate), | ||
469 | [DECODE_TYPE_OR] = sizeof(struct decode_or), | ||
470 | [DECODE_TYPE_REJECT] = sizeof(struct decode_reject) | ||
471 | }; | ||
472 | |||
473 | /* | ||
474 | * kprobe_decode_insn operates on data tables in order to decode an ARM | ||
475 | * architecture instruction onto which a kprobe has been placed. | ||
476 | * | ||
477 | * These instruction decoding tables are a concatenation of entries each | ||
478 | * of which consist of one of the following structs: | ||
479 | * | ||
480 | * decode_table | ||
481 | * decode_custom | ||
482 | * decode_simulate | ||
483 | * decode_emulate | ||
484 | * decode_or | ||
485 | * decode_reject | ||
486 | * | ||
487 | * Each of these starts with a struct decode_header which has the following | ||
488 | * fields: | ||
489 | * | ||
490 | * type_regs | ||
491 | * mask | ||
492 | * value | ||
493 | * | ||
494 | * The least significant DECODE_TYPE_BITS of type_regs contains a value | ||
495 | * from enum decode_type, this indicates which of the decode_* structs | ||
496 | * the entry contains. The value DECODE_TYPE_END indicates the end of the | ||
497 | * table. | ||
498 | * | ||
499 | * When the table is parsed, each entry is checked in turn to see if it | ||
500 | * matches the instruction to be decoded using the test: | ||
501 | * | ||
502 | * (insn & mask) == value | ||
503 | * | ||
504 | * If no match is found before the end of the table is reached then decoding | ||
505 | * fails with INSN_REJECTED. | ||
506 | * | ||
507 | * When a match is found, decode_regs() is called to validate and modify each | ||
508 | * of the registers encoded in the instruction; the data it uses to do this | ||
509 | * is (type_regs >> DECODE_TYPE_BITS). A validation failure will cause decoding | ||
510 | * to fail with INSN_REJECTED. | ||
511 | * | ||
512 | * Once the instruction has passed the above tests, further processing | ||
513 | * depends on the type of the table entry's decode struct. | ||
514 | * | ||
515 | */ | ||
516 | int __kprobes | ||
517 | kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, | ||
518 | const union decode_item *table, bool thumb) | ||
519 | { | ||
520 | const struct decode_header *h = (struct decode_header *)table; | ||
521 | const struct decode_header *next; | ||
522 | bool matched = false; | ||
523 | |||
524 | insn = prepare_emulated_insn(insn, asi, thumb); | ||
525 | |||
526 | for (;; h = next) { | ||
527 | enum decode_type type = h->type_regs.bits & DECODE_TYPE_MASK; | ||
528 | u32 regs = h->type_regs.bits >> DECODE_TYPE_BITS; | ||
529 | |||
530 | if (type == DECODE_TYPE_END) | ||
531 | return INSN_REJECTED; | ||
532 | |||
533 | next = (struct decode_header *) | ||
534 | ((uintptr_t)h + decode_struct_sizes[type]); | ||
535 | |||
536 | if (!matched && (insn & h->mask.bits) != h->value.bits) | ||
537 | continue; | ||
538 | |||
539 | if (!decode_regs(&insn, regs)) | ||
540 | return INSN_REJECTED; | ||
541 | |||
542 | switch (type) { | ||
543 | |||
544 | case DECODE_TYPE_TABLE: { | ||
545 | struct decode_table *d = (struct decode_table *)h; | ||
546 | next = (struct decode_header *)d->table.table; | ||
547 | break; | ||
548 | } | ||
549 | |||
550 | case DECODE_TYPE_CUSTOM: { | ||
551 | struct decode_custom *d = (struct decode_custom *)h; | ||
552 | return (*d->decoder.decoder)(insn, asi); | ||
553 | } | ||
554 | |||
555 | case DECODE_TYPE_SIMULATE: { | ||
556 | struct decode_simulate *d = (struct decode_simulate *)h; | ||
557 | asi->insn_handler = d->handler.handler; | ||
558 | return INSN_GOOD_NO_SLOT; | ||
559 | } | ||
560 | |||
561 | case DECODE_TYPE_EMULATE: { | ||
562 | struct decode_emulate *d = (struct decode_emulate *)h; | ||
563 | asi->insn_handler = d->handler.handler; | ||
564 | set_emulated_insn(insn, asi, thumb); | ||
565 | return INSN_GOOD; | ||
566 | } | ||
567 | |||
568 | case DECODE_TYPE_OR: | ||
569 | matched = true; | ||
570 | break; | ||
571 | |||
572 | case DECODE_TYPE_REJECT: | ||
573 | default: | ||
574 | return INSN_REJECTED; | ||
575 | } | ||
576 | } | ||
577 | } | ||
diff --git a/arch/arm/kernel/kprobes-decode.c b/arch/arm/kernel/kprobes-decode.c deleted file mode 100644 index 15eeff6aea0e..000000000000 --- a/arch/arm/kernel/kprobes-decode.c +++ /dev/null | |||
@@ -1,1670 +0,0 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/kprobes-decode.c | ||
3 | * | ||
4 | * Copyright (C) 2006, 2007 Motorola Inc. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
13 | * General Public License for more details. | ||
14 | */ | ||
15 | |||
16 | /* | ||
17 | * We do not have hardware single-stepping on ARM, This | ||
18 | * effort is further complicated by the ARM not having a | ||
19 | * "next PC" register. Instructions that change the PC | ||
20 | * can't be safely single-stepped in a MP environment, so | ||
21 | * we have a lot of work to do: | ||
22 | * | ||
23 | * In the prepare phase: | ||
24 | * *) If it is an instruction that does anything | ||
25 | * with the CPU mode, we reject it for a kprobe. | ||
26 | * (This is out of laziness rather than need. The | ||
27 | * instructions could be simulated.) | ||
28 | * | ||
29 | * *) Otherwise, decode the instruction rewriting its | ||
30 | * registers to take fixed, ordered registers and | ||
31 | * setting a handler for it to run the instruction. | ||
32 | * | ||
33 | * In the execution phase by an instruction's handler: | ||
34 | * | ||
35 | * *) If the PC is written to by the instruction, the | ||
36 | * instruction must be fully simulated in software. | ||
37 | * | ||
38 | * *) Otherwise, a modified form of the instruction is | ||
39 | * directly executed. Its handler calls the | ||
40 | * instruction in insn[0]. In insn[1] is a | ||
41 | * "mov pc, lr" to return. | ||
42 | * | ||
43 | * Before calling, load up the reordered registers | ||
44 | * from the original instruction's registers. If one | ||
45 | * of the original input registers is the PC, compute | ||
46 | * and adjust the appropriate input register. | ||
47 | * | ||
48 | * After call completes, copy the output registers to | ||
49 | * the original instruction's original registers. | ||
50 | * | ||
51 | * We don't use a real breakpoint instruction since that | ||
52 | * would have us in the kernel go from SVC mode to SVC | ||
53 | * mode losing the link register. Instead we use an | ||
54 | * undefined instruction. To simplify processing, the | ||
55 | * undefined instruction used for kprobes must be reserved | ||
56 | * exclusively for kprobes use. | ||
57 | * | ||
58 | * TODO: ifdef out some instruction decoding based on architecture. | ||
59 | */ | ||
60 | |||
61 | #include <linux/kernel.h> | ||
62 | #include <linux/kprobes.h> | ||
63 | |||
64 | #define sign_extend(x, signbit) ((x) | (0 - ((x) & (1 << (signbit))))) | ||
65 | |||
66 | #define branch_displacement(insn) sign_extend(((insn) & 0xffffff) << 2, 25) | ||
67 | |||
68 | #define is_r15(insn, bitpos) (((insn) & (0xf << bitpos)) == (0xf << bitpos)) | ||
69 | |||
70 | /* | ||
71 | * Test if load/store instructions writeback the address register. | ||
72 | * if P (bit 24) == 0 or W (bit 21) == 1 | ||
73 | */ | ||
74 | #define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) | ||
75 | |||
76 | #define PSR_fs (PSR_f|PSR_s) | ||
77 | |||
78 | #define KPROBE_RETURN_INSTRUCTION 0xe1a0f00e /* mov pc, lr */ | ||
79 | |||
80 | typedef long (insn_0arg_fn_t)(void); | ||
81 | typedef long (insn_1arg_fn_t)(long); | ||
82 | typedef long (insn_2arg_fn_t)(long, long); | ||
83 | typedef long (insn_3arg_fn_t)(long, long, long); | ||
84 | typedef long (insn_4arg_fn_t)(long, long, long, long); | ||
85 | typedef long long (insn_llret_0arg_fn_t)(void); | ||
86 | typedef long long (insn_llret_3arg_fn_t)(long, long, long); | ||
87 | typedef long long (insn_llret_4arg_fn_t)(long, long, long, long); | ||
88 | |||
89 | union reg_pair { | ||
90 | long long dr; | ||
91 | #ifdef __LITTLE_ENDIAN | ||
92 | struct { long r0, r1; }; | ||
93 | #else | ||
94 | struct { long r1, r0; }; | ||
95 | #endif | ||
96 | }; | ||
97 | |||
98 | /* | ||
99 | * For STR and STM instructions, an ARM core may choose to use either | ||
100 | * a +8 or a +12 displacement from the current instruction's address. | ||
101 | * Whichever value is chosen for a given core, it must be the same for | ||
102 | * both instructions and may not change. This function measures it. | ||
103 | */ | ||
104 | |||
105 | static int str_pc_offset; | ||
106 | |||
107 | static void __init find_str_pc_offset(void) | ||
108 | { | ||
109 | int addr, scratch, ret; | ||
110 | |||
111 | __asm__ ( | ||
112 | "sub %[ret], pc, #4 \n\t" | ||
113 | "str pc, %[addr] \n\t" | ||
114 | "ldr %[scr], %[addr] \n\t" | ||
115 | "sub %[ret], %[scr], %[ret] \n\t" | ||
116 | : [ret] "=r" (ret), [scr] "=r" (scratch), [addr] "+m" (addr)); | ||
117 | |||
118 | str_pc_offset = ret; | ||
119 | } | ||
120 | |||
121 | /* | ||
122 | * The insnslot_?arg_r[w]flags() functions below are to keep the | ||
123 | * msr -> *fn -> mrs instruction sequences indivisible so that | ||
124 | * the state of the CPSR flags aren't inadvertently modified | ||
125 | * just before or just after the call. | ||
126 | */ | ||
127 | |||
128 | static inline long __kprobes | ||
129 | insnslot_0arg_rflags(long cpsr, insn_0arg_fn_t *fn) | ||
130 | { | ||
131 | register long ret asm("r0"); | ||
132 | |||
133 | __asm__ __volatile__ ( | ||
134 | "msr cpsr_fs, %[cpsr] \n\t" | ||
135 | "mov lr, pc \n\t" | ||
136 | "mov pc, %[fn] \n\t" | ||
137 | : "=r" (ret) | ||
138 | : [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
139 | : "lr", "cc" | ||
140 | ); | ||
141 | return ret; | ||
142 | } | ||
143 | |||
144 | static inline long long __kprobes | ||
145 | insnslot_llret_0arg_rflags(long cpsr, insn_llret_0arg_fn_t *fn) | ||
146 | { | ||
147 | register long ret0 asm("r0"); | ||
148 | register long ret1 asm("r1"); | ||
149 | union reg_pair fnr; | ||
150 | |||
151 | __asm__ __volatile__ ( | ||
152 | "msr cpsr_fs, %[cpsr] \n\t" | ||
153 | "mov lr, pc \n\t" | ||
154 | "mov pc, %[fn] \n\t" | ||
155 | : "=r" (ret0), "=r" (ret1) | ||
156 | : [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
157 | : "lr", "cc" | ||
158 | ); | ||
159 | fnr.r0 = ret0; | ||
160 | fnr.r1 = ret1; | ||
161 | return fnr.dr; | ||
162 | } | ||
163 | |||
164 | static inline long __kprobes | ||
165 | insnslot_1arg_rflags(long r0, long cpsr, insn_1arg_fn_t *fn) | ||
166 | { | ||
167 | register long rr0 asm("r0") = r0; | ||
168 | register long ret asm("r0"); | ||
169 | |||
170 | __asm__ __volatile__ ( | ||
171 | "msr cpsr_fs, %[cpsr] \n\t" | ||
172 | "mov lr, pc \n\t" | ||
173 | "mov pc, %[fn] \n\t" | ||
174 | : "=r" (ret) | ||
175 | : "0" (rr0), [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
176 | : "lr", "cc" | ||
177 | ); | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | static inline long __kprobes | ||
182 | insnslot_2arg_rflags(long r0, long r1, long cpsr, insn_2arg_fn_t *fn) | ||
183 | { | ||
184 | register long rr0 asm("r0") = r0; | ||
185 | register long rr1 asm("r1") = r1; | ||
186 | register long ret asm("r0"); | ||
187 | |||
188 | __asm__ __volatile__ ( | ||
189 | "msr cpsr_fs, %[cpsr] \n\t" | ||
190 | "mov lr, pc \n\t" | ||
191 | "mov pc, %[fn] \n\t" | ||
192 | : "=r" (ret) | ||
193 | : "0" (rr0), "r" (rr1), | ||
194 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
195 | : "lr", "cc" | ||
196 | ); | ||
197 | return ret; | ||
198 | } | ||
199 | |||
200 | static inline long __kprobes | ||
201 | insnslot_3arg_rflags(long r0, long r1, long r2, long cpsr, insn_3arg_fn_t *fn) | ||
202 | { | ||
203 | register long rr0 asm("r0") = r0; | ||
204 | register long rr1 asm("r1") = r1; | ||
205 | register long rr2 asm("r2") = r2; | ||
206 | register long ret asm("r0"); | ||
207 | |||
208 | __asm__ __volatile__ ( | ||
209 | "msr cpsr_fs, %[cpsr] \n\t" | ||
210 | "mov lr, pc \n\t" | ||
211 | "mov pc, %[fn] \n\t" | ||
212 | : "=r" (ret) | ||
213 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
214 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
215 | : "lr", "cc" | ||
216 | ); | ||
217 | return ret; | ||
218 | } | ||
219 | |||
220 | static inline long long __kprobes | ||
221 | insnslot_llret_3arg_rflags(long r0, long r1, long r2, long cpsr, | ||
222 | insn_llret_3arg_fn_t *fn) | ||
223 | { | ||
224 | register long rr0 asm("r0") = r0; | ||
225 | register long rr1 asm("r1") = r1; | ||
226 | register long rr2 asm("r2") = r2; | ||
227 | register long ret0 asm("r0"); | ||
228 | register long ret1 asm("r1"); | ||
229 | union reg_pair fnr; | ||
230 | |||
231 | __asm__ __volatile__ ( | ||
232 | "msr cpsr_fs, %[cpsr] \n\t" | ||
233 | "mov lr, pc \n\t" | ||
234 | "mov pc, %[fn] \n\t" | ||
235 | : "=r" (ret0), "=r" (ret1) | ||
236 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
237 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
238 | : "lr", "cc" | ||
239 | ); | ||
240 | fnr.r0 = ret0; | ||
241 | fnr.r1 = ret1; | ||
242 | return fnr.dr; | ||
243 | } | ||
244 | |||
245 | static inline long __kprobes | ||
246 | insnslot_4arg_rflags(long r0, long r1, long r2, long r3, long cpsr, | ||
247 | insn_4arg_fn_t *fn) | ||
248 | { | ||
249 | register long rr0 asm("r0") = r0; | ||
250 | register long rr1 asm("r1") = r1; | ||
251 | register long rr2 asm("r2") = r2; | ||
252 | register long rr3 asm("r3") = r3; | ||
253 | register long ret asm("r0"); | ||
254 | |||
255 | __asm__ __volatile__ ( | ||
256 | "msr cpsr_fs, %[cpsr] \n\t" | ||
257 | "mov lr, pc \n\t" | ||
258 | "mov pc, %[fn] \n\t" | ||
259 | : "=r" (ret) | ||
260 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
261 | [cpsr] "r" (cpsr), [fn] "r" (fn) | ||
262 | : "lr", "cc" | ||
263 | ); | ||
264 | return ret; | ||
265 | } | ||
266 | |||
267 | static inline long __kprobes | ||
268 | insnslot_1arg_rwflags(long r0, long *cpsr, insn_1arg_fn_t *fn) | ||
269 | { | ||
270 | register long rr0 asm("r0") = r0; | ||
271 | register long ret asm("r0"); | ||
272 | long oldcpsr = *cpsr; | ||
273 | long newcpsr; | ||
274 | |||
275 | __asm__ __volatile__ ( | ||
276 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
277 | "mov lr, pc \n\t" | ||
278 | "mov pc, %[fn] \n\t" | ||
279 | "mrs %[newcpsr], cpsr \n\t" | ||
280 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
281 | : "0" (rr0), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
282 | : "lr", "cc" | ||
283 | ); | ||
284 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
285 | return ret; | ||
286 | } | ||
287 | |||
288 | static inline long __kprobes | ||
289 | insnslot_2arg_rwflags(long r0, long r1, long *cpsr, insn_2arg_fn_t *fn) | ||
290 | { | ||
291 | register long rr0 asm("r0") = r0; | ||
292 | register long rr1 asm("r1") = r1; | ||
293 | register long ret asm("r0"); | ||
294 | long oldcpsr = *cpsr; | ||
295 | long newcpsr; | ||
296 | |||
297 | __asm__ __volatile__ ( | ||
298 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
299 | "mov lr, pc \n\t" | ||
300 | "mov pc, %[fn] \n\t" | ||
301 | "mrs %[newcpsr], cpsr \n\t" | ||
302 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
303 | : "0" (rr0), "r" (rr1), [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
304 | : "lr", "cc" | ||
305 | ); | ||
306 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
307 | return ret; | ||
308 | } | ||
309 | |||
310 | static inline long __kprobes | ||
311 | insnslot_3arg_rwflags(long r0, long r1, long r2, long *cpsr, | ||
312 | insn_3arg_fn_t *fn) | ||
313 | { | ||
314 | register long rr0 asm("r0") = r0; | ||
315 | register long rr1 asm("r1") = r1; | ||
316 | register long rr2 asm("r2") = r2; | ||
317 | register long ret asm("r0"); | ||
318 | long oldcpsr = *cpsr; | ||
319 | long newcpsr; | ||
320 | |||
321 | __asm__ __volatile__ ( | ||
322 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
323 | "mov lr, pc \n\t" | ||
324 | "mov pc, %[fn] \n\t" | ||
325 | "mrs %[newcpsr], cpsr \n\t" | ||
326 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
327 | : "0" (rr0), "r" (rr1), "r" (rr2), | ||
328 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
329 | : "lr", "cc" | ||
330 | ); | ||
331 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
332 | return ret; | ||
333 | } | ||
334 | |||
335 | static inline long __kprobes | ||
336 | insnslot_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, | ||
337 | insn_4arg_fn_t *fn) | ||
338 | { | ||
339 | register long rr0 asm("r0") = r0; | ||
340 | register long rr1 asm("r1") = r1; | ||
341 | register long rr2 asm("r2") = r2; | ||
342 | register long rr3 asm("r3") = r3; | ||
343 | register long ret asm("r0"); | ||
344 | long oldcpsr = *cpsr; | ||
345 | long newcpsr; | ||
346 | |||
347 | __asm__ __volatile__ ( | ||
348 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
349 | "mov lr, pc \n\t" | ||
350 | "mov pc, %[fn] \n\t" | ||
351 | "mrs %[newcpsr], cpsr \n\t" | ||
352 | : "=r" (ret), [newcpsr] "=r" (newcpsr) | ||
353 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
354 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
355 | : "lr", "cc" | ||
356 | ); | ||
357 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | static inline long long __kprobes | ||
362 | insnslot_llret_4arg_rwflags(long r0, long r1, long r2, long r3, long *cpsr, | ||
363 | insn_llret_4arg_fn_t *fn) | ||
364 | { | ||
365 | register long rr0 asm("r0") = r0; | ||
366 | register long rr1 asm("r1") = r1; | ||
367 | register long rr2 asm("r2") = r2; | ||
368 | register long rr3 asm("r3") = r3; | ||
369 | register long ret0 asm("r0"); | ||
370 | register long ret1 asm("r1"); | ||
371 | long oldcpsr = *cpsr; | ||
372 | long newcpsr; | ||
373 | union reg_pair fnr; | ||
374 | |||
375 | __asm__ __volatile__ ( | ||
376 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
377 | "mov lr, pc \n\t" | ||
378 | "mov pc, %[fn] \n\t" | ||
379 | "mrs %[newcpsr], cpsr \n\t" | ||
380 | : "=r" (ret0), "=r" (ret1), [newcpsr] "=r" (newcpsr) | ||
381 | : "0" (rr0), "r" (rr1), "r" (rr2), "r" (rr3), | ||
382 | [oldcpsr] "r" (oldcpsr), [fn] "r" (fn) | ||
383 | : "lr", "cc" | ||
384 | ); | ||
385 | *cpsr = (oldcpsr & ~PSR_fs) | (newcpsr & PSR_fs); | ||
386 | fnr.r0 = ret0; | ||
387 | fnr.r1 = ret1; | ||
388 | return fnr.dr; | ||
389 | } | ||
390 | |||
391 | /* | ||
392 | * To avoid the complications of mimicing single-stepping on a | ||
393 | * processor without a Next-PC or a single-step mode, and to | ||
394 | * avoid having to deal with the side-effects of boosting, we | ||
395 | * simulate or emulate (almost) all ARM instructions. | ||
396 | * | ||
397 | * "Simulation" is where the instruction's behavior is duplicated in | ||
398 | * C code. "Emulation" is where the original instruction is rewritten | ||
399 | * and executed, often by altering its registers. | ||
400 | * | ||
401 | * By having all behavior of the kprobe'd instruction completed before | ||
402 | * returning from the kprobe_handler(), all locks (scheduler and | ||
403 | * interrupt) can safely be released. There is no need for secondary | ||
404 | * breakpoints, no race with MP or preemptable kernels, nor having to | ||
405 | * clean up resources counts at a later time impacting overall system | ||
406 | * performance. By rewriting the instruction, only the minimum registers | ||
407 | * need to be loaded and saved back optimizing performance. | ||
408 | * | ||
409 | * Calling the insnslot_*_rwflags version of a function doesn't hurt | ||
410 | * anything even when the CPSR flags aren't updated by the | ||
411 | * instruction. It's just a little slower in return for saving | ||
412 | * a little space by not having a duplicate function that doesn't | ||
413 | * update the flags. (The same optimization can be said for | ||
414 | * instructions that do or don't perform register writeback) | ||
415 | * Also, instructions can either read the flags, only write the | ||
416 | * flags, or read and write the flags. To save combinations | ||
417 | * rather than for sheer performance, flag functions just assume | ||
418 | * read and write of flags. | ||
419 | */ | ||
420 | |||
421 | static void __kprobes simulate_bbl(struct kprobe *p, struct pt_regs *regs) | ||
422 | { | ||
423 | kprobe_opcode_t insn = p->opcode; | ||
424 | long iaddr = (long)p->addr; | ||
425 | int disp = branch_displacement(insn); | ||
426 | |||
427 | if (insn & (1 << 24)) | ||
428 | regs->ARM_lr = iaddr + 4; | ||
429 | |||
430 | regs->ARM_pc = iaddr + 8 + disp; | ||
431 | } | ||
432 | |||
433 | static void __kprobes simulate_blx1(struct kprobe *p, struct pt_regs *regs) | ||
434 | { | ||
435 | kprobe_opcode_t insn = p->opcode; | ||
436 | long iaddr = (long)p->addr; | ||
437 | int disp = branch_displacement(insn); | ||
438 | |||
439 | regs->ARM_lr = iaddr + 4; | ||
440 | regs->ARM_pc = iaddr + 8 + disp + ((insn >> 23) & 0x2); | ||
441 | regs->ARM_cpsr |= PSR_T_BIT; | ||
442 | } | ||
443 | |||
444 | static void __kprobes simulate_blx2bx(struct kprobe *p, struct pt_regs *regs) | ||
445 | { | ||
446 | kprobe_opcode_t insn = p->opcode; | ||
447 | int rm = insn & 0xf; | ||
448 | long rmv = regs->uregs[rm]; | ||
449 | |||
450 | if (insn & (1 << 5)) | ||
451 | regs->ARM_lr = (long)p->addr + 4; | ||
452 | |||
453 | regs->ARM_pc = rmv & ~0x1; | ||
454 | regs->ARM_cpsr &= ~PSR_T_BIT; | ||
455 | if (rmv & 0x1) | ||
456 | regs->ARM_cpsr |= PSR_T_BIT; | ||
457 | } | ||
458 | |||
459 | static void __kprobes simulate_mrs(struct kprobe *p, struct pt_regs *regs) | ||
460 | { | ||
461 | kprobe_opcode_t insn = p->opcode; | ||
462 | int rd = (insn >> 12) & 0xf; | ||
463 | unsigned long mask = 0xf8ff03df; /* Mask out execution state */ | ||
464 | regs->uregs[rd] = regs->ARM_cpsr & mask; | ||
465 | } | ||
466 | |||
467 | static void __kprobes simulate_ldm1stm1(struct kprobe *p, struct pt_regs *regs) | ||
468 | { | ||
469 | kprobe_opcode_t insn = p->opcode; | ||
470 | int rn = (insn >> 16) & 0xf; | ||
471 | int lbit = insn & (1 << 20); | ||
472 | int wbit = insn & (1 << 21); | ||
473 | int ubit = insn & (1 << 23); | ||
474 | int pbit = insn & (1 << 24); | ||
475 | long *addr = (long *)regs->uregs[rn]; | ||
476 | int reg_bit_vector; | ||
477 | int reg_count; | ||
478 | |||
479 | reg_count = 0; | ||
480 | reg_bit_vector = insn & 0xffff; | ||
481 | while (reg_bit_vector) { | ||
482 | reg_bit_vector &= (reg_bit_vector - 1); | ||
483 | ++reg_count; | ||
484 | } | ||
485 | |||
486 | if (!ubit) | ||
487 | addr -= reg_count; | ||
488 | addr += (!pbit == !ubit); | ||
489 | |||
490 | reg_bit_vector = insn & 0xffff; | ||
491 | while (reg_bit_vector) { | ||
492 | int reg = __ffs(reg_bit_vector); | ||
493 | reg_bit_vector &= (reg_bit_vector - 1); | ||
494 | if (lbit) | ||
495 | regs->uregs[reg] = *addr++; | ||
496 | else | ||
497 | *addr++ = regs->uregs[reg]; | ||
498 | } | ||
499 | |||
500 | if (wbit) { | ||
501 | if (!ubit) | ||
502 | addr -= reg_count; | ||
503 | addr -= (!pbit == !ubit); | ||
504 | regs->uregs[rn] = (long)addr; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | static void __kprobes simulate_stm1_pc(struct kprobe *p, struct pt_regs *regs) | ||
509 | { | ||
510 | regs->ARM_pc = (long)p->addr + str_pc_offset; | ||
511 | simulate_ldm1stm1(p, regs); | ||
512 | regs->ARM_pc = (long)p->addr + 4; | ||
513 | } | ||
514 | |||
515 | static void __kprobes simulate_mov_ipsp(struct kprobe *p, struct pt_regs *regs) | ||
516 | { | ||
517 | regs->uregs[12] = regs->uregs[13]; | ||
518 | } | ||
519 | |||
520 | static void __kprobes emulate_ldrd(struct kprobe *p, struct pt_regs *regs) | ||
521 | { | ||
522 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
523 | kprobe_opcode_t insn = p->opcode; | ||
524 | long ppc = (long)p->addr + 8; | ||
525 | int rd = (insn >> 12) & 0xf; | ||
526 | int rn = (insn >> 16) & 0xf; | ||
527 | int rm = insn & 0xf; /* rm may be invalid, don't care. */ | ||
528 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
529 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
530 | |||
531 | /* Not following the C calling convention here, so need asm(). */ | ||
532 | __asm__ __volatile__ ( | ||
533 | "ldr r0, %[rn] \n\t" | ||
534 | "ldr r1, %[rm] \n\t" | ||
535 | "msr cpsr_fs, %[cpsr]\n\t" | ||
536 | "mov lr, pc \n\t" | ||
537 | "mov pc, %[i_fn] \n\t" | ||
538 | "str r0, %[rn] \n\t" /* in case of writeback */ | ||
539 | "str r2, %[rd0] \n\t" | ||
540 | "str r3, %[rd1] \n\t" | ||
541 | : [rn] "+m" (rnv), | ||
542 | [rd0] "=m" (regs->uregs[rd]), | ||
543 | [rd1] "=m" (regs->uregs[rd+1]) | ||
544 | : [rm] "m" (rmv), | ||
545 | [cpsr] "r" (regs->ARM_cpsr), | ||
546 | [i_fn] "r" (i_fn) | ||
547 | : "r0", "r1", "r2", "r3", "lr", "cc" | ||
548 | ); | ||
549 | if (is_writeback(insn)) | ||
550 | regs->uregs[rn] = rnv; | ||
551 | } | ||
552 | |||
553 | static void __kprobes emulate_strd(struct kprobe *p, struct pt_regs *regs) | ||
554 | { | ||
555 | insn_4arg_fn_t *i_fn = (insn_4arg_fn_t *)&p->ainsn.insn[0]; | ||
556 | kprobe_opcode_t insn = p->opcode; | ||
557 | long ppc = (long)p->addr + 8; | ||
558 | int rd = (insn >> 12) & 0xf; | ||
559 | int rn = (insn >> 16) & 0xf; | ||
560 | int rm = insn & 0xf; | ||
561 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
562 | /* rm/rmv may be invalid, don't care. */ | ||
563 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
564 | long rnv_wb; | ||
565 | |||
566 | rnv_wb = insnslot_4arg_rflags(rnv, rmv, regs->uregs[rd], | ||
567 | regs->uregs[rd+1], | ||
568 | regs->ARM_cpsr, i_fn); | ||
569 | if (is_writeback(insn)) | ||
570 | regs->uregs[rn] = rnv_wb; | ||
571 | } | ||
572 | |||
573 | static void __kprobes emulate_ldr(struct kprobe *p, struct pt_regs *regs) | ||
574 | { | ||
575 | insn_llret_3arg_fn_t *i_fn = (insn_llret_3arg_fn_t *)&p->ainsn.insn[0]; | ||
576 | kprobe_opcode_t insn = p->opcode; | ||
577 | long ppc = (long)p->addr + 8; | ||
578 | union reg_pair fnr; | ||
579 | int rd = (insn >> 12) & 0xf; | ||
580 | int rn = (insn >> 16) & 0xf; | ||
581 | int rm = insn & 0xf; | ||
582 | long rdv; | ||
583 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
584 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
585 | long cpsr = regs->ARM_cpsr; | ||
586 | |||
587 | fnr.dr = insnslot_llret_3arg_rflags(rnv, 0, rmv, cpsr, i_fn); | ||
588 | if (rn != 15) | ||
589 | regs->uregs[rn] = fnr.r0; /* Save Rn in case of writeback. */ | ||
590 | rdv = fnr.r1; | ||
591 | |||
592 | if (rd == 15) { | ||
593 | #if __LINUX_ARM_ARCH__ >= 5 | ||
594 | cpsr &= ~PSR_T_BIT; | ||
595 | if (rdv & 0x1) | ||
596 | cpsr |= PSR_T_BIT; | ||
597 | regs->ARM_cpsr = cpsr; | ||
598 | rdv &= ~0x1; | ||
599 | #else | ||
600 | rdv &= ~0x2; | ||
601 | #endif | ||
602 | } | ||
603 | regs->uregs[rd] = rdv; | ||
604 | } | ||
605 | |||
606 | static void __kprobes emulate_str(struct kprobe *p, struct pt_regs *regs) | ||
607 | { | ||
608 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
609 | kprobe_opcode_t insn = p->opcode; | ||
610 | long iaddr = (long)p->addr; | ||
611 | int rd = (insn >> 12) & 0xf; | ||
612 | int rn = (insn >> 16) & 0xf; | ||
613 | int rm = insn & 0xf; | ||
614 | long rdv = (rd == 15) ? iaddr + str_pc_offset : regs->uregs[rd]; | ||
615 | long rnv = (rn == 15) ? iaddr + 8 : regs->uregs[rn]; | ||
616 | long rmv = regs->uregs[rm]; /* rm/rmv may be invalid, don't care. */ | ||
617 | long rnv_wb; | ||
618 | |||
619 | rnv_wb = insnslot_3arg_rflags(rnv, rdv, rmv, regs->ARM_cpsr, i_fn); | ||
620 | if (rn != 15) | ||
621 | regs->uregs[rn] = rnv_wb; /* Save Rn in case of writeback. */ | ||
622 | } | ||
623 | |||
624 | static void __kprobes emulate_sat(struct kprobe *p, struct pt_regs *regs) | ||
625 | { | ||
626 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
627 | kprobe_opcode_t insn = p->opcode; | ||
628 | int rd = (insn >> 12) & 0xf; | ||
629 | int rm = insn & 0xf; | ||
630 | long rmv = regs->uregs[rm]; | ||
631 | |||
632 | /* Writes Q flag */ | ||
633 | regs->uregs[rd] = insnslot_1arg_rwflags(rmv, ®s->ARM_cpsr, i_fn); | ||
634 | } | ||
635 | |||
636 | static void __kprobes emulate_sel(struct kprobe *p, struct pt_regs *regs) | ||
637 | { | ||
638 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
639 | kprobe_opcode_t insn = p->opcode; | ||
640 | int rd = (insn >> 12) & 0xf; | ||
641 | int rn = (insn >> 16) & 0xf; | ||
642 | int rm = insn & 0xf; | ||
643 | long rnv = regs->uregs[rn]; | ||
644 | long rmv = regs->uregs[rm]; | ||
645 | |||
646 | /* Reads GE bits */ | ||
647 | regs->uregs[rd] = insnslot_2arg_rflags(rnv, rmv, regs->ARM_cpsr, i_fn); | ||
648 | } | ||
649 | |||
650 | static void __kprobes emulate_none(struct kprobe *p, struct pt_regs *regs) | ||
651 | { | ||
652 | insn_0arg_fn_t *i_fn = (insn_0arg_fn_t *)&p->ainsn.insn[0]; | ||
653 | |||
654 | insnslot_0arg_rflags(regs->ARM_cpsr, i_fn); | ||
655 | } | ||
656 | |||
657 | static void __kprobes emulate_nop(struct kprobe *p, struct pt_regs *regs) | ||
658 | { | ||
659 | } | ||
660 | |||
661 | static void __kprobes | ||
662 | emulate_rd12_modify(struct kprobe *p, struct pt_regs *regs) | ||
663 | { | ||
664 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
665 | kprobe_opcode_t insn = p->opcode; | ||
666 | int rd = (insn >> 12) & 0xf; | ||
667 | long rdv = regs->uregs[rd]; | ||
668 | |||
669 | regs->uregs[rd] = insnslot_1arg_rflags(rdv, regs->ARM_cpsr, i_fn); | ||
670 | } | ||
671 | |||
672 | static void __kprobes | ||
673 | emulate_rd12rn0_modify(struct kprobe *p, struct pt_regs *regs) | ||
674 | { | ||
675 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
676 | kprobe_opcode_t insn = p->opcode; | ||
677 | int rd = (insn >> 12) & 0xf; | ||
678 | int rn = insn & 0xf; | ||
679 | long rdv = regs->uregs[rd]; | ||
680 | long rnv = regs->uregs[rn]; | ||
681 | |||
682 | regs->uregs[rd] = insnslot_2arg_rflags(rdv, rnv, regs->ARM_cpsr, i_fn); | ||
683 | } | ||
684 | |||
685 | static void __kprobes emulate_rd12rm0(struct kprobe *p, struct pt_regs *regs) | ||
686 | { | ||
687 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
688 | kprobe_opcode_t insn = p->opcode; | ||
689 | int rd = (insn >> 12) & 0xf; | ||
690 | int rm = insn & 0xf; | ||
691 | long rmv = regs->uregs[rm]; | ||
692 | |||
693 | regs->uregs[rd] = insnslot_1arg_rflags(rmv, regs->ARM_cpsr, i_fn); | ||
694 | } | ||
695 | |||
696 | static void __kprobes | ||
697 | emulate_rd12rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
698 | { | ||
699 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
700 | kprobe_opcode_t insn = p->opcode; | ||
701 | int rd = (insn >> 12) & 0xf; | ||
702 | int rn = (insn >> 16) & 0xf; | ||
703 | int rm = insn & 0xf; | ||
704 | long rnv = regs->uregs[rn]; | ||
705 | long rmv = regs->uregs[rm]; | ||
706 | |||
707 | regs->uregs[rd] = | ||
708 | insnslot_2arg_rwflags(rnv, rmv, ®s->ARM_cpsr, i_fn); | ||
709 | } | ||
710 | |||
711 | static void __kprobes | ||
712 | emulate_rd16rn12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
713 | { | ||
714 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
715 | kprobe_opcode_t insn = p->opcode; | ||
716 | int rd = (insn >> 16) & 0xf; | ||
717 | int rn = (insn >> 12) & 0xf; | ||
718 | int rs = (insn >> 8) & 0xf; | ||
719 | int rm = insn & 0xf; | ||
720 | long rnv = regs->uregs[rn]; | ||
721 | long rsv = regs->uregs[rs]; | ||
722 | long rmv = regs->uregs[rm]; | ||
723 | |||
724 | regs->uregs[rd] = | ||
725 | insnslot_3arg_rwflags(rnv, rsv, rmv, ®s->ARM_cpsr, i_fn); | ||
726 | } | ||
727 | |||
728 | static void __kprobes | ||
729 | emulate_rd16rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
730 | { | ||
731 | insn_2arg_fn_t *i_fn = (insn_2arg_fn_t *)&p->ainsn.insn[0]; | ||
732 | kprobe_opcode_t insn = p->opcode; | ||
733 | int rd = (insn >> 16) & 0xf; | ||
734 | int rs = (insn >> 8) & 0xf; | ||
735 | int rm = insn & 0xf; | ||
736 | long rsv = regs->uregs[rs]; | ||
737 | long rmv = regs->uregs[rm]; | ||
738 | |||
739 | regs->uregs[rd] = | ||
740 | insnslot_2arg_rwflags(rsv, rmv, ®s->ARM_cpsr, i_fn); | ||
741 | } | ||
742 | |||
743 | static void __kprobes | ||
744 | emulate_rdhi16rdlo12rs8rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
745 | { | ||
746 | insn_llret_4arg_fn_t *i_fn = (insn_llret_4arg_fn_t *)&p->ainsn.insn[0]; | ||
747 | kprobe_opcode_t insn = p->opcode; | ||
748 | union reg_pair fnr; | ||
749 | int rdhi = (insn >> 16) & 0xf; | ||
750 | int rdlo = (insn >> 12) & 0xf; | ||
751 | int rs = (insn >> 8) & 0xf; | ||
752 | int rm = insn & 0xf; | ||
753 | long rsv = regs->uregs[rs]; | ||
754 | long rmv = regs->uregs[rm]; | ||
755 | |||
756 | fnr.dr = insnslot_llret_4arg_rwflags(regs->uregs[rdhi], | ||
757 | regs->uregs[rdlo], rsv, rmv, | ||
758 | ®s->ARM_cpsr, i_fn); | ||
759 | regs->uregs[rdhi] = fnr.r0; | ||
760 | regs->uregs[rdlo] = fnr.r1; | ||
761 | } | ||
762 | |||
763 | static void __kprobes | ||
764 | emulate_alu_imm_rflags(struct kprobe *p, struct pt_regs *regs) | ||
765 | { | ||
766 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
767 | kprobe_opcode_t insn = p->opcode; | ||
768 | int rd = (insn >> 12) & 0xf; | ||
769 | int rn = (insn >> 16) & 0xf; | ||
770 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
771 | |||
772 | regs->uregs[rd] = insnslot_1arg_rflags(rnv, regs->ARM_cpsr, i_fn); | ||
773 | } | ||
774 | |||
775 | static void __kprobes | ||
776 | emulate_alu_imm_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
777 | { | ||
778 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
779 | kprobe_opcode_t insn = p->opcode; | ||
780 | int rd = (insn >> 12) & 0xf; | ||
781 | int rn = (insn >> 16) & 0xf; | ||
782 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
783 | |||
784 | regs->uregs[rd] = insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); | ||
785 | } | ||
786 | |||
787 | static void __kprobes | ||
788 | emulate_alu_tests_imm(struct kprobe *p, struct pt_regs *regs) | ||
789 | { | ||
790 | insn_1arg_fn_t *i_fn = (insn_1arg_fn_t *)&p->ainsn.insn[0]; | ||
791 | kprobe_opcode_t insn = p->opcode; | ||
792 | int rn = (insn >> 16) & 0xf; | ||
793 | long rnv = (rn == 15) ? (long)p->addr + 8 : regs->uregs[rn]; | ||
794 | |||
795 | insnslot_1arg_rwflags(rnv, ®s->ARM_cpsr, i_fn); | ||
796 | } | ||
797 | |||
798 | static void __kprobes | ||
799 | emulate_alu_rflags(struct kprobe *p, struct pt_regs *regs) | ||
800 | { | ||
801 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
802 | kprobe_opcode_t insn = p->opcode; | ||
803 | long ppc = (long)p->addr + 8; | ||
804 | int rd = (insn >> 12) & 0xf; | ||
805 | int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ | ||
806 | int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ | ||
807 | int rm = insn & 0xf; | ||
808 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
809 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
810 | long rsv = regs->uregs[rs]; | ||
811 | |||
812 | regs->uregs[rd] = | ||
813 | insnslot_3arg_rflags(rnv, rmv, rsv, regs->ARM_cpsr, i_fn); | ||
814 | } | ||
815 | |||
816 | static void __kprobes | ||
817 | emulate_alu_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
818 | { | ||
819 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
820 | kprobe_opcode_t insn = p->opcode; | ||
821 | long ppc = (long)p->addr + 8; | ||
822 | int rd = (insn >> 12) & 0xf; | ||
823 | int rn = (insn >> 16) & 0xf; /* rn/rnv/rs/rsv may be */ | ||
824 | int rs = (insn >> 8) & 0xf; /* invalid, don't care. */ | ||
825 | int rm = insn & 0xf; | ||
826 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
827 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
828 | long rsv = regs->uregs[rs]; | ||
829 | |||
830 | regs->uregs[rd] = | ||
831 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); | ||
832 | } | ||
833 | |||
834 | static void __kprobes | ||
835 | emulate_alu_tests(struct kprobe *p, struct pt_regs *regs) | ||
836 | { | ||
837 | insn_3arg_fn_t *i_fn = (insn_3arg_fn_t *)&p->ainsn.insn[0]; | ||
838 | kprobe_opcode_t insn = p->opcode; | ||
839 | long ppc = (long)p->addr + 8; | ||
840 | int rn = (insn >> 16) & 0xf; | ||
841 | int rs = (insn >> 8) & 0xf; /* rs/rsv may be invalid, don't care. */ | ||
842 | int rm = insn & 0xf; | ||
843 | long rnv = (rn == 15) ? ppc : regs->uregs[rn]; | ||
844 | long rmv = (rm == 15) ? ppc : regs->uregs[rm]; | ||
845 | long rsv = regs->uregs[rs]; | ||
846 | |||
847 | insnslot_3arg_rwflags(rnv, rmv, rsv, ®s->ARM_cpsr, i_fn); | ||
848 | } | ||
849 | |||
850 | static enum kprobe_insn __kprobes | ||
851 | prep_emulate_ldr_str(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
852 | { | ||
853 | int not_imm = (insn & (1 << 26)) ? (insn & (1 << 25)) | ||
854 | : (~insn & (1 << 22)); | ||
855 | |||
856 | if (is_writeback(insn) && is_r15(insn, 16)) | ||
857 | return INSN_REJECTED; /* Writeback to PC */ | ||
858 | |||
859 | insn &= 0xfff00fff; | ||
860 | insn |= 0x00001000; /* Rn = r0, Rd = r1 */ | ||
861 | if (not_imm) { | ||
862 | insn &= ~0xf; | ||
863 | insn |= 2; /* Rm = r2 */ | ||
864 | } | ||
865 | asi->insn[0] = insn; | ||
866 | asi->insn_handler = (insn & (1 << 20)) ? emulate_ldr : emulate_str; | ||
867 | return INSN_GOOD; | ||
868 | } | ||
869 | |||
870 | static enum kprobe_insn __kprobes | ||
871 | prep_emulate_rd12_modify(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
872 | { | ||
873 | if (is_r15(insn, 12)) | ||
874 | return INSN_REJECTED; /* Rd is PC */ | ||
875 | |||
876 | insn &= 0xffff0fff; /* Rd = r0 */ | ||
877 | asi->insn[0] = insn; | ||
878 | asi->insn_handler = emulate_rd12_modify; | ||
879 | return INSN_GOOD; | ||
880 | } | ||
881 | |||
882 | static enum kprobe_insn __kprobes | ||
883 | prep_emulate_rd12rn0_modify(kprobe_opcode_t insn, | ||
884 | struct arch_specific_insn *asi) | ||
885 | { | ||
886 | if (is_r15(insn, 12)) | ||
887 | return INSN_REJECTED; /* Rd is PC */ | ||
888 | |||
889 | insn &= 0xffff0ff0; /* Rd = r0 */ | ||
890 | insn |= 0x00000001; /* Rn = r1 */ | ||
891 | asi->insn[0] = insn; | ||
892 | asi->insn_handler = emulate_rd12rn0_modify; | ||
893 | return INSN_GOOD; | ||
894 | } | ||
895 | |||
896 | static enum kprobe_insn __kprobes | ||
897 | prep_emulate_rd12rm0(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
898 | { | ||
899 | if (is_r15(insn, 12)) | ||
900 | return INSN_REJECTED; /* Rd is PC */ | ||
901 | |||
902 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | ||
903 | asi->insn[0] = insn; | ||
904 | asi->insn_handler = emulate_rd12rm0; | ||
905 | return INSN_GOOD; | ||
906 | } | ||
907 | |||
908 | static enum kprobe_insn __kprobes | ||
909 | prep_emulate_rd12rn16rm0_wflags(kprobe_opcode_t insn, | ||
910 | struct arch_specific_insn *asi) | ||
911 | { | ||
912 | if (is_r15(insn, 12)) | ||
913 | return INSN_REJECTED; /* Rd is PC */ | ||
914 | |||
915 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | ||
916 | insn |= 0x00000001; /* Rm = r1 */ | ||
917 | asi->insn[0] = insn; | ||
918 | asi->insn_handler = emulate_rd12rn16rm0_rwflags; | ||
919 | return INSN_GOOD; | ||
920 | } | ||
921 | |||
922 | static enum kprobe_insn __kprobes | ||
923 | prep_emulate_rd16rs8rm0_wflags(kprobe_opcode_t insn, | ||
924 | struct arch_specific_insn *asi) | ||
925 | { | ||
926 | if (is_r15(insn, 16)) | ||
927 | return INSN_REJECTED; /* Rd is PC */ | ||
928 | |||
929 | insn &= 0xfff0f0f0; /* Rd = r0, Rs = r0 */ | ||
930 | insn |= 0x00000001; /* Rm = r1 */ | ||
931 | asi->insn[0] = insn; | ||
932 | asi->insn_handler = emulate_rd16rs8rm0_rwflags; | ||
933 | return INSN_GOOD; | ||
934 | } | ||
935 | |||
936 | static enum kprobe_insn __kprobes | ||
937 | prep_emulate_rd16rn12rs8rm0_wflags(kprobe_opcode_t insn, | ||
938 | struct arch_specific_insn *asi) | ||
939 | { | ||
940 | if (is_r15(insn, 16)) | ||
941 | return INSN_REJECTED; /* Rd is PC */ | ||
942 | |||
943 | insn &= 0xfff000f0; /* Rd = r0, Rn = r0 */ | ||
944 | insn |= 0x00000102; /* Rs = r1, Rm = r2 */ | ||
945 | asi->insn[0] = insn; | ||
946 | asi->insn_handler = emulate_rd16rn12rs8rm0_rwflags; | ||
947 | return INSN_GOOD; | ||
948 | } | ||
949 | |||
950 | static enum kprobe_insn __kprobes | ||
951 | prep_emulate_rdhi16rdlo12rs8rm0_wflags(kprobe_opcode_t insn, | ||
952 | struct arch_specific_insn *asi) | ||
953 | { | ||
954 | if (is_r15(insn, 16) || is_r15(insn, 12)) | ||
955 | return INSN_REJECTED; /* RdHi or RdLo is PC */ | ||
956 | |||
957 | insn &= 0xfff000f0; /* RdHi = r0, RdLo = r1 */ | ||
958 | insn |= 0x00001203; /* Rs = r2, Rm = r3 */ | ||
959 | asi->insn[0] = insn; | ||
960 | asi->insn_handler = emulate_rdhi16rdlo12rs8rm0_rwflags; | ||
961 | return INSN_GOOD; | ||
962 | } | ||
963 | |||
964 | /* | ||
965 | * For the instruction masking and comparisons in all the "space_*" | ||
966 | * functions below, Do _not_ rearrange the order of tests unless | ||
967 | * you're very, very sure of what you are doing. For the sake of | ||
968 | * efficiency, the masks for some tests sometimes assume other test | ||
969 | * have been done prior to them so the number of patterns to test | ||
970 | * for an instruction set can be as broad as possible to reduce the | ||
971 | * number of tests needed. | ||
972 | */ | ||
973 | |||
974 | static enum kprobe_insn __kprobes | ||
975 | space_1111(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
976 | { | ||
977 | /* memory hint : 1111 0100 x001 xxxx xxxx xxxx xxxx xxxx : */ | ||
978 | /* PLDI : 1111 0100 x101 xxxx xxxx xxxx xxxx xxxx : */ | ||
979 | /* PLDW : 1111 0101 x001 xxxx xxxx xxxx xxxx xxxx : */ | ||
980 | /* PLD : 1111 0101 x101 xxxx xxxx xxxx xxxx xxxx : */ | ||
981 | if ((insn & 0xfe300000) == 0xf4100000) { | ||
982 | asi->insn_handler = emulate_nop; | ||
983 | return INSN_GOOD_NO_SLOT; | ||
984 | } | ||
985 | |||
986 | /* BLX(1) : 1111 101x xxxx xxxx xxxx xxxx xxxx xxxx : */ | ||
987 | if ((insn & 0xfe000000) == 0xfa000000) { | ||
988 | asi->insn_handler = simulate_blx1; | ||
989 | return INSN_GOOD_NO_SLOT; | ||
990 | } | ||
991 | |||
992 | /* CPS : 1111 0001 0000 xxx0 xxxx xxxx xx0x xxxx */ | ||
993 | /* SETEND: 1111 0001 0000 0001 xxxx xxxx 0000 xxxx */ | ||
994 | |||
995 | /* SRS : 1111 100x x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
996 | /* RFE : 1111 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
997 | |||
998 | /* Coprocessor instructions... */ | ||
999 | /* MCRR2 : 1111 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | ||
1000 | /* MRRC2 : 1111 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd != Rn) */ | ||
1001 | /* LDC2 : 1111 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
1002 | /* STC2 : 1111 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
1003 | /* CDP2 : 1111 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
1004 | /* MCR2 : 1111 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
1005 | /* MRC2 : 1111 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
1006 | |||
1007 | return INSN_REJECTED; | ||
1008 | } | ||
1009 | |||
1010 | static enum kprobe_insn __kprobes | ||
1011 | space_cccc_000x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1012 | { | ||
1013 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
1014 | if ((insn & 0x0f900010) == 0x01000000) { | ||
1015 | |||
1016 | /* MRS cpsr : cccc 0001 0000 xxxx xxxx xxxx 0000 xxxx */ | ||
1017 | if ((insn & 0x0ff000f0) == 0x01000000) { | ||
1018 | if (is_r15(insn, 12)) | ||
1019 | return INSN_REJECTED; /* Rd is PC */ | ||
1020 | asi->insn_handler = simulate_mrs; | ||
1021 | return INSN_GOOD_NO_SLOT; | ||
1022 | } | ||
1023 | |||
1024 | /* SMLALxy : cccc 0001 0100 xxxx xxxx xxxx 1xx0 xxxx */ | ||
1025 | if ((insn & 0x0ff00090) == 0x01400080) | ||
1026 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, | ||
1027 | asi); | ||
1028 | |||
1029 | /* SMULWy : cccc 0001 0010 xxxx xxxx xxxx 1x10 xxxx */ | ||
1030 | /* SMULxy : cccc 0001 0110 xxxx xxxx xxxx 1xx0 xxxx */ | ||
1031 | if ((insn & 0x0ff000b0) == 0x012000a0 || | ||
1032 | (insn & 0x0ff00090) == 0x01600080) | ||
1033 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | ||
1034 | |||
1035 | /* SMLAxy : cccc 0001 0000 xxxx xxxx xxxx 1xx0 xxxx : Q */ | ||
1036 | /* SMLAWy : cccc 0001 0010 xxxx xxxx xxxx 1x00 xxxx : Q */ | ||
1037 | if ((insn & 0x0ff00090) == 0x01000080 || | ||
1038 | (insn & 0x0ff000b0) == 0x01200080) | ||
1039 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1040 | |||
1041 | /* BXJ : cccc 0001 0010 xxxx xxxx xxxx 0010 xxxx */ | ||
1042 | /* MSR : cccc 0001 0x10 xxxx xxxx xxxx 0000 xxxx */ | ||
1043 | /* MRS spsr : cccc 0001 0100 xxxx xxxx xxxx 0000 xxxx */ | ||
1044 | |||
1045 | /* Other instruction encodings aren't yet defined */ | ||
1046 | return INSN_REJECTED; | ||
1047 | } | ||
1048 | |||
1049 | /* cccc 0001 0xx0 xxxx xxxx xxxx xxxx 0xx1 xxxx */ | ||
1050 | else if ((insn & 0x0f900090) == 0x01000010) { | ||
1051 | |||
1052 | /* BLX(2) : cccc 0001 0010 xxxx xxxx xxxx 0011 xxxx */ | ||
1053 | /* BX : cccc 0001 0010 xxxx xxxx xxxx 0001 xxxx */ | ||
1054 | if ((insn & 0x0ff000d0) == 0x01200010) { | ||
1055 | if ((insn & 0x0ff000ff) == 0x0120003f) | ||
1056 | return INSN_REJECTED; /* BLX pc */ | ||
1057 | asi->insn_handler = simulate_blx2bx; | ||
1058 | return INSN_GOOD_NO_SLOT; | ||
1059 | } | ||
1060 | |||
1061 | /* CLZ : cccc 0001 0110 xxxx xxxx xxxx 0001 xxxx */ | ||
1062 | if ((insn & 0x0ff000f0) == 0x01600010) | ||
1063 | return prep_emulate_rd12rm0(insn, asi); | ||
1064 | |||
1065 | /* QADD : cccc 0001 0000 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1066 | /* QSUB : cccc 0001 0010 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1067 | /* QDADD : cccc 0001 0100 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1068 | /* QDSUB : cccc 0001 0110 xxxx xxxx xxxx 0101 xxxx :Q */ | ||
1069 | if ((insn & 0x0f9000f0) == 0x01000050) | ||
1070 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1071 | |||
1072 | /* BKPT : 1110 0001 0010 xxxx xxxx xxxx 0111 xxxx */ | ||
1073 | /* SMC : cccc 0001 0110 xxxx xxxx xxxx 0111 xxxx */ | ||
1074 | |||
1075 | /* Other instruction encodings aren't yet defined */ | ||
1076 | return INSN_REJECTED; | ||
1077 | } | ||
1078 | |||
1079 | /* cccc 0000 xxxx xxxx xxxx xxxx xxxx 1001 xxxx */ | ||
1080 | else if ((insn & 0x0f0000f0) == 0x00000090) { | ||
1081 | |||
1082 | /* MUL : cccc 0000 0000 xxxx xxxx xxxx 1001 xxxx : */ | ||
1083 | /* MULS : cccc 0000 0001 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1084 | /* MLA : cccc 0000 0010 xxxx xxxx xxxx 1001 xxxx : */ | ||
1085 | /* MLAS : cccc 0000 0011 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1086 | /* UMAAL : cccc 0000 0100 xxxx xxxx xxxx 1001 xxxx : */ | ||
1087 | /* undef : cccc 0000 0101 xxxx xxxx xxxx 1001 xxxx : */ | ||
1088 | /* MLS : cccc 0000 0110 xxxx xxxx xxxx 1001 xxxx : */ | ||
1089 | /* undef : cccc 0000 0111 xxxx xxxx xxxx 1001 xxxx : */ | ||
1090 | /* UMULL : cccc 0000 1000 xxxx xxxx xxxx 1001 xxxx : */ | ||
1091 | /* UMULLS : cccc 0000 1001 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1092 | /* UMLAL : cccc 0000 1010 xxxx xxxx xxxx 1001 xxxx : */ | ||
1093 | /* UMLALS : cccc 0000 1011 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1094 | /* SMULL : cccc 0000 1100 xxxx xxxx xxxx 1001 xxxx : */ | ||
1095 | /* SMULLS : cccc 0000 1101 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1096 | /* SMLAL : cccc 0000 1110 xxxx xxxx xxxx 1001 xxxx : */ | ||
1097 | /* SMLALS : cccc 0000 1111 xxxx xxxx xxxx 1001 xxxx :cc */ | ||
1098 | if ((insn & 0x00d00000) == 0x00500000) | ||
1099 | return INSN_REJECTED; | ||
1100 | else if ((insn & 0x00e00000) == 0x00000000) | ||
1101 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | ||
1102 | else if ((insn & 0x00a00000) == 0x00200000) | ||
1103 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1104 | else | ||
1105 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, | ||
1106 | asi); | ||
1107 | } | ||
1108 | |||
1109 | /* cccc 000x xxxx xxxx xxxx xxxx xxxx 1xx1 xxxx */ | ||
1110 | else if ((insn & 0x0e000090) == 0x00000090) { | ||
1111 | |||
1112 | /* SWP : cccc 0001 0000 xxxx xxxx xxxx 1001 xxxx */ | ||
1113 | /* SWPB : cccc 0001 0100 xxxx xxxx xxxx 1001 xxxx */ | ||
1114 | /* ??? : cccc 0001 0x01 xxxx xxxx xxxx 1001 xxxx */ | ||
1115 | /* ??? : cccc 0001 0x10 xxxx xxxx xxxx 1001 xxxx */ | ||
1116 | /* ??? : cccc 0001 0x11 xxxx xxxx xxxx 1001 xxxx */ | ||
1117 | /* STREX : cccc 0001 1000 xxxx xxxx xxxx 1001 xxxx */ | ||
1118 | /* LDREX : cccc 0001 1001 xxxx xxxx xxxx 1001 xxxx */ | ||
1119 | /* STREXD: cccc 0001 1010 xxxx xxxx xxxx 1001 xxxx */ | ||
1120 | /* LDREXD: cccc 0001 1011 xxxx xxxx xxxx 1001 xxxx */ | ||
1121 | /* STREXB: cccc 0001 1100 xxxx xxxx xxxx 1001 xxxx */ | ||
1122 | /* LDREXB: cccc 0001 1101 xxxx xxxx xxxx 1001 xxxx */ | ||
1123 | /* STREXH: cccc 0001 1110 xxxx xxxx xxxx 1001 xxxx */ | ||
1124 | /* LDREXH: cccc 0001 1111 xxxx xxxx xxxx 1001 xxxx */ | ||
1125 | |||
1126 | /* LDRD : cccc 000x xxx0 xxxx xxxx xxxx 1101 xxxx */ | ||
1127 | /* STRD : cccc 000x xxx0 xxxx xxxx xxxx 1111 xxxx */ | ||
1128 | /* LDRH : cccc 000x xxx1 xxxx xxxx xxxx 1011 xxxx */ | ||
1129 | /* STRH : cccc 000x xxx0 xxxx xxxx xxxx 1011 xxxx */ | ||
1130 | /* LDRSB : cccc 000x xxx1 xxxx xxxx xxxx 1101 xxxx */ | ||
1131 | /* LDRSH : cccc 000x xxx1 xxxx xxxx xxxx 1111 xxxx */ | ||
1132 | if ((insn & 0x0f0000f0) == 0x01000090) { | ||
1133 | if ((insn & 0x0fb000f0) == 0x01000090) { | ||
1134 | /* SWP/SWPB */ | ||
1135 | return prep_emulate_rd12rn16rm0_wflags(insn, | ||
1136 | asi); | ||
1137 | } else { | ||
1138 | /* STREX/LDREX variants and unallocaed space */ | ||
1139 | return INSN_REJECTED; | ||
1140 | } | ||
1141 | |||
1142 | } else if ((insn & 0x0e1000d0) == 0x00000d0) { | ||
1143 | /* STRD/LDRD */ | ||
1144 | if ((insn & 0x0000e000) == 0x0000e000) | ||
1145 | return INSN_REJECTED; /* Rd is LR or PC */ | ||
1146 | if (is_writeback(insn) && is_r15(insn, 16)) | ||
1147 | return INSN_REJECTED; /* Writeback to PC */ | ||
1148 | |||
1149 | insn &= 0xfff00fff; | ||
1150 | insn |= 0x00002000; /* Rn = r0, Rd = r2 */ | ||
1151 | if (!(insn & (1 << 22))) { | ||
1152 | /* Register index */ | ||
1153 | insn &= ~0xf; | ||
1154 | insn |= 1; /* Rm = r1 */ | ||
1155 | } | ||
1156 | asi->insn[0] = insn; | ||
1157 | asi->insn_handler = | ||
1158 | (insn & (1 << 5)) ? emulate_strd : emulate_ldrd; | ||
1159 | return INSN_GOOD; | ||
1160 | } | ||
1161 | |||
1162 | /* LDRH/STRH/LDRSB/LDRSH */ | ||
1163 | if (is_r15(insn, 12)) | ||
1164 | return INSN_REJECTED; /* Rd is PC */ | ||
1165 | return prep_emulate_ldr_str(insn, asi); | ||
1166 | } | ||
1167 | |||
1168 | /* cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1169 | |||
1170 | /* | ||
1171 | * ALU op with S bit and Rd == 15 : | ||
1172 | * cccc 000x xxx1 xxxx 1111 xxxx xxxx xxxx | ||
1173 | */ | ||
1174 | if ((insn & 0x0e10f000) == 0x0010f000) | ||
1175 | return INSN_REJECTED; | ||
1176 | |||
1177 | /* | ||
1178 | * "mov ip, sp" is the most common kprobe'd instruction by far. | ||
1179 | * Check and optimize for it explicitly. | ||
1180 | */ | ||
1181 | if (insn == 0xe1a0c00d) { | ||
1182 | asi->insn_handler = simulate_mov_ipsp; | ||
1183 | return INSN_GOOD_NO_SLOT; | ||
1184 | } | ||
1185 | |||
1186 | /* | ||
1187 | * Data processing: Immediate-shift / Register-shift | ||
1188 | * ALU op : cccc 000x xxxx xxxx xxxx xxxx xxxx xxxx | ||
1189 | * CPY : cccc 0001 1010 xxxx xxxx 0000 0000 xxxx | ||
1190 | * MOV : cccc 0001 101x xxxx xxxx xxxx xxxx xxxx | ||
1191 | * *S (bit 20) updates condition codes | ||
1192 | * ADC/SBC/RSC reads the C flag | ||
1193 | */ | ||
1194 | insn &= 0xfff00ff0; /* Rn = r0, Rd = r0 */ | ||
1195 | insn |= 0x00000001; /* Rm = r1 */ | ||
1196 | if (insn & 0x010) { | ||
1197 | insn &= 0xfffff0ff; /* register shift */ | ||
1198 | insn |= 0x00000200; /* Rs = r2 */ | ||
1199 | } | ||
1200 | asi->insn[0] = insn; | ||
1201 | |||
1202 | if ((insn & 0x0f900000) == 0x01100000) { | ||
1203 | /* | ||
1204 | * TST : cccc 0001 0001 xxxx xxxx xxxx xxxx xxxx | ||
1205 | * TEQ : cccc 0001 0011 xxxx xxxx xxxx xxxx xxxx | ||
1206 | * CMP : cccc 0001 0101 xxxx xxxx xxxx xxxx xxxx | ||
1207 | * CMN : cccc 0001 0111 xxxx xxxx xxxx xxxx xxxx | ||
1208 | */ | ||
1209 | asi->insn_handler = emulate_alu_tests; | ||
1210 | } else { | ||
1211 | /* ALU ops which write to Rd */ | ||
1212 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | ||
1213 | emulate_alu_rwflags : emulate_alu_rflags; | ||
1214 | } | ||
1215 | return INSN_GOOD; | ||
1216 | } | ||
1217 | |||
1218 | static enum kprobe_insn __kprobes | ||
1219 | space_cccc_001x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1220 | { | ||
1221 | /* MOVW : cccc 0011 0000 xxxx xxxx xxxx xxxx xxxx */ | ||
1222 | /* MOVT : cccc 0011 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
1223 | if ((insn & 0x0fb00000) == 0x03000000) | ||
1224 | return prep_emulate_rd12_modify(insn, asi); | ||
1225 | |||
1226 | /* hints : cccc 0011 0010 0000 xxxx xxxx xxxx xxxx */ | ||
1227 | if ((insn & 0x0fff0000) == 0x03200000) { | ||
1228 | unsigned op2 = insn & 0x000000ff; | ||
1229 | if (op2 == 0x01 || op2 == 0x04) { | ||
1230 | /* YIELD : cccc 0011 0010 0000 xxxx xxxx 0000 0001 */ | ||
1231 | /* SEV : cccc 0011 0010 0000 xxxx xxxx 0000 0100 */ | ||
1232 | asi->insn[0] = insn; | ||
1233 | asi->insn_handler = emulate_none; | ||
1234 | return INSN_GOOD; | ||
1235 | } else if (op2 <= 0x03) { | ||
1236 | /* NOP : cccc 0011 0010 0000 xxxx xxxx 0000 0000 */ | ||
1237 | /* WFE : cccc 0011 0010 0000 xxxx xxxx 0000 0010 */ | ||
1238 | /* WFI : cccc 0011 0010 0000 xxxx xxxx 0000 0011 */ | ||
1239 | /* | ||
1240 | * We make WFE and WFI true NOPs to avoid stalls due | ||
1241 | * to missing events whilst processing the probe. | ||
1242 | */ | ||
1243 | asi->insn_handler = emulate_nop; | ||
1244 | return INSN_GOOD_NO_SLOT; | ||
1245 | } | ||
1246 | /* For DBG and unallocated hints it's safest to reject them */ | ||
1247 | return INSN_REJECTED; | ||
1248 | } | ||
1249 | |||
1250 | /* | ||
1251 | * MSR : cccc 0011 0x10 xxxx xxxx xxxx xxxx xxxx | ||
1252 | * ALU op with S bit and Rd == 15 : | ||
1253 | * cccc 001x xxx1 xxxx 1111 xxxx xxxx xxxx | ||
1254 | */ | ||
1255 | if ((insn & 0x0fb00000) == 0x03200000 || /* MSR */ | ||
1256 | (insn & 0x0e10f000) == 0x0210f000) /* ALU s-bit, R15 */ | ||
1257 | return INSN_REJECTED; | ||
1258 | |||
1259 | /* | ||
1260 | * Data processing: 32-bit Immediate | ||
1261 | * ALU op : cccc 001x xxxx xxxx xxxx xxxx xxxx xxxx | ||
1262 | * MOV : cccc 0011 101x xxxx xxxx xxxx xxxx xxxx | ||
1263 | * *S (bit 20) updates condition codes | ||
1264 | * ADC/SBC/RSC reads the C flag | ||
1265 | */ | ||
1266 | insn &= 0xfff00fff; /* Rn = r0 and Rd = r0 */ | ||
1267 | asi->insn[0] = insn; | ||
1268 | |||
1269 | if ((insn & 0x0f900000) == 0x03100000) { | ||
1270 | /* | ||
1271 | * TST : cccc 0011 0001 xxxx xxxx xxxx xxxx xxxx | ||
1272 | * TEQ : cccc 0011 0011 xxxx xxxx xxxx xxxx xxxx | ||
1273 | * CMP : cccc 0011 0101 xxxx xxxx xxxx xxxx xxxx | ||
1274 | * CMN : cccc 0011 0111 xxxx xxxx xxxx xxxx xxxx | ||
1275 | */ | ||
1276 | asi->insn_handler = emulate_alu_tests_imm; | ||
1277 | } else { | ||
1278 | /* ALU ops which write to Rd */ | ||
1279 | asi->insn_handler = (insn & (1 << 20)) ? /* S-bit */ | ||
1280 | emulate_alu_imm_rwflags : emulate_alu_imm_rflags; | ||
1281 | } | ||
1282 | return INSN_GOOD; | ||
1283 | } | ||
1284 | |||
1285 | static enum kprobe_insn __kprobes | ||
1286 | space_cccc_0110__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1287 | { | ||
1288 | /* SEL : cccc 0110 1000 xxxx xxxx xxxx 1011 xxxx GE: !!! */ | ||
1289 | if ((insn & 0x0ff000f0) == 0x068000b0) { | ||
1290 | if (is_r15(insn, 12)) | ||
1291 | return INSN_REJECTED; /* Rd is PC */ | ||
1292 | insn &= 0xfff00ff0; /* Rd = r0, Rn = r0 */ | ||
1293 | insn |= 0x00000001; /* Rm = r1 */ | ||
1294 | asi->insn[0] = insn; | ||
1295 | asi->insn_handler = emulate_sel; | ||
1296 | return INSN_GOOD; | ||
1297 | } | ||
1298 | |||
1299 | /* SSAT : cccc 0110 101x xxxx xxxx xxxx xx01 xxxx :Q */ | ||
1300 | /* USAT : cccc 0110 111x xxxx xxxx xxxx xx01 xxxx :Q */ | ||
1301 | /* SSAT16 : cccc 0110 1010 xxxx xxxx xxxx 0011 xxxx :Q */ | ||
1302 | /* USAT16 : cccc 0110 1110 xxxx xxxx xxxx 0011 xxxx :Q */ | ||
1303 | if ((insn & 0x0fa00030) == 0x06a00010 || | ||
1304 | (insn & 0x0fb000f0) == 0x06a00030) { | ||
1305 | if (is_r15(insn, 12)) | ||
1306 | return INSN_REJECTED; /* Rd is PC */ | ||
1307 | insn &= 0xffff0ff0; /* Rd = r0, Rm = r0 */ | ||
1308 | asi->insn[0] = insn; | ||
1309 | asi->insn_handler = emulate_sat; | ||
1310 | return INSN_GOOD; | ||
1311 | } | ||
1312 | |||
1313 | /* REV : cccc 0110 1011 xxxx xxxx xxxx 0011 xxxx */ | ||
1314 | /* REV16 : cccc 0110 1011 xxxx xxxx xxxx 1011 xxxx */ | ||
1315 | /* RBIT : cccc 0110 1111 xxxx xxxx xxxx 0011 xxxx */ | ||
1316 | /* REVSH : cccc 0110 1111 xxxx xxxx xxxx 1011 xxxx */ | ||
1317 | if ((insn & 0x0ff00070) == 0x06b00030 || | ||
1318 | (insn & 0x0ff00070) == 0x06f00030) | ||
1319 | return prep_emulate_rd12rm0(insn, asi); | ||
1320 | |||
1321 | /* ??? : cccc 0110 0000 xxxx xxxx xxxx xxx1 xxxx : */ | ||
1322 | /* SADD16 : cccc 0110 0001 xxxx xxxx xxxx 0001 xxxx :GE */ | ||
1323 | /* SADDSUBX : cccc 0110 0001 xxxx xxxx xxxx 0011 xxxx :GE */ | ||
1324 | /* SSUBADDX : cccc 0110 0001 xxxx xxxx xxxx 0101 xxxx :GE */ | ||
1325 | /* SSUB16 : cccc 0110 0001 xxxx xxxx xxxx 0111 xxxx :GE */ | ||
1326 | /* SADD8 : cccc 0110 0001 xxxx xxxx xxxx 1001 xxxx :GE */ | ||
1327 | /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1011 xxxx : */ | ||
1328 | /* ??? : cccc 0110 0001 xxxx xxxx xxxx 1101 xxxx : */ | ||
1329 | /* SSUB8 : cccc 0110 0001 xxxx xxxx xxxx 1111 xxxx :GE */ | ||
1330 | /* QADD16 : cccc 0110 0010 xxxx xxxx xxxx 0001 xxxx : */ | ||
1331 | /* QADDSUBX : cccc 0110 0010 xxxx xxxx xxxx 0011 xxxx : */ | ||
1332 | /* QSUBADDX : cccc 0110 0010 xxxx xxxx xxxx 0101 xxxx : */ | ||
1333 | /* QSUB16 : cccc 0110 0010 xxxx xxxx xxxx 0111 xxxx : */ | ||
1334 | /* QADD8 : cccc 0110 0010 xxxx xxxx xxxx 1001 xxxx : */ | ||
1335 | /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1011 xxxx : */ | ||
1336 | /* ??? : cccc 0110 0010 xxxx xxxx xxxx 1101 xxxx : */ | ||
1337 | /* QSUB8 : cccc 0110 0010 xxxx xxxx xxxx 1111 xxxx : */ | ||
1338 | /* SHADD16 : cccc 0110 0011 xxxx xxxx xxxx 0001 xxxx : */ | ||
1339 | /* SHADDSUBX : cccc 0110 0011 xxxx xxxx xxxx 0011 xxxx : */ | ||
1340 | /* SHSUBADDX : cccc 0110 0011 xxxx xxxx xxxx 0101 xxxx : */ | ||
1341 | /* SHSUB16 : cccc 0110 0011 xxxx xxxx xxxx 0111 xxxx : */ | ||
1342 | /* SHADD8 : cccc 0110 0011 xxxx xxxx xxxx 1001 xxxx : */ | ||
1343 | /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1011 xxxx : */ | ||
1344 | /* ??? : cccc 0110 0011 xxxx xxxx xxxx 1101 xxxx : */ | ||
1345 | /* SHSUB8 : cccc 0110 0011 xxxx xxxx xxxx 1111 xxxx : */ | ||
1346 | /* ??? : cccc 0110 0100 xxxx xxxx xxxx xxx1 xxxx : */ | ||
1347 | /* UADD16 : cccc 0110 0101 xxxx xxxx xxxx 0001 xxxx :GE */ | ||
1348 | /* UADDSUBX : cccc 0110 0101 xxxx xxxx xxxx 0011 xxxx :GE */ | ||
1349 | /* USUBADDX : cccc 0110 0101 xxxx xxxx xxxx 0101 xxxx :GE */ | ||
1350 | /* USUB16 : cccc 0110 0101 xxxx xxxx xxxx 0111 xxxx :GE */ | ||
1351 | /* UADD8 : cccc 0110 0101 xxxx xxxx xxxx 1001 xxxx :GE */ | ||
1352 | /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1011 xxxx : */ | ||
1353 | /* ??? : cccc 0110 0101 xxxx xxxx xxxx 1101 xxxx : */ | ||
1354 | /* USUB8 : cccc 0110 0101 xxxx xxxx xxxx 1111 xxxx :GE */ | ||
1355 | /* UQADD16 : cccc 0110 0110 xxxx xxxx xxxx 0001 xxxx : */ | ||
1356 | /* UQADDSUBX : cccc 0110 0110 xxxx xxxx xxxx 0011 xxxx : */ | ||
1357 | /* UQSUBADDX : cccc 0110 0110 xxxx xxxx xxxx 0101 xxxx : */ | ||
1358 | /* UQSUB16 : cccc 0110 0110 xxxx xxxx xxxx 0111 xxxx : */ | ||
1359 | /* UQADD8 : cccc 0110 0110 xxxx xxxx xxxx 1001 xxxx : */ | ||
1360 | /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1011 xxxx : */ | ||
1361 | /* ??? : cccc 0110 0110 xxxx xxxx xxxx 1101 xxxx : */ | ||
1362 | /* UQSUB8 : cccc 0110 0110 xxxx xxxx xxxx 1111 xxxx : */ | ||
1363 | /* UHADD16 : cccc 0110 0111 xxxx xxxx xxxx 0001 xxxx : */ | ||
1364 | /* UHADDSUBX : cccc 0110 0111 xxxx xxxx xxxx 0011 xxxx : */ | ||
1365 | /* UHSUBADDX : cccc 0110 0111 xxxx xxxx xxxx 0101 xxxx : */ | ||
1366 | /* UHSUB16 : cccc 0110 0111 xxxx xxxx xxxx 0111 xxxx : */ | ||
1367 | /* UHADD8 : cccc 0110 0111 xxxx xxxx xxxx 1001 xxxx : */ | ||
1368 | /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1011 xxxx : */ | ||
1369 | /* ??? : cccc 0110 0111 xxxx xxxx xxxx 1101 xxxx : */ | ||
1370 | /* UHSUB8 : cccc 0110 0111 xxxx xxxx xxxx 1111 xxxx : */ | ||
1371 | if ((insn & 0x0f800010) == 0x06000010) { | ||
1372 | if ((insn & 0x00300000) == 0x00000000 || | ||
1373 | (insn & 0x000000e0) == 0x000000a0 || | ||
1374 | (insn & 0x000000e0) == 0x000000c0) | ||
1375 | return INSN_REJECTED; /* Unallocated space */ | ||
1376 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1377 | } | ||
1378 | |||
1379 | /* PKHBT : cccc 0110 1000 xxxx xxxx xxxx x001 xxxx : */ | ||
1380 | /* PKHTB : cccc 0110 1000 xxxx xxxx xxxx x101 xxxx : */ | ||
1381 | if ((insn & 0x0ff00030) == 0x06800010) | ||
1382 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1383 | |||
1384 | /* SXTAB16 : cccc 0110 1000 xxxx xxxx xxxx 0111 xxxx : */ | ||
1385 | /* SXTB16 : cccc 0110 1000 1111 xxxx xxxx 0111 xxxx : */ | ||
1386 | /* ??? : cccc 0110 1001 xxxx xxxx xxxx 0111 xxxx : */ | ||
1387 | /* SXTAB : cccc 0110 1010 xxxx xxxx xxxx 0111 xxxx : */ | ||
1388 | /* SXTB : cccc 0110 1010 1111 xxxx xxxx 0111 xxxx : */ | ||
1389 | /* SXTAH : cccc 0110 1011 xxxx xxxx xxxx 0111 xxxx : */ | ||
1390 | /* SXTH : cccc 0110 1011 1111 xxxx xxxx 0111 xxxx : */ | ||
1391 | /* UXTAB16 : cccc 0110 1100 xxxx xxxx xxxx 0111 xxxx : */ | ||
1392 | /* UXTB16 : cccc 0110 1100 1111 xxxx xxxx 0111 xxxx : */ | ||
1393 | /* ??? : cccc 0110 1101 xxxx xxxx xxxx 0111 xxxx : */ | ||
1394 | /* UXTAB : cccc 0110 1110 xxxx xxxx xxxx 0111 xxxx : */ | ||
1395 | /* UXTB : cccc 0110 1110 1111 xxxx xxxx 0111 xxxx : */ | ||
1396 | /* UXTAH : cccc 0110 1111 xxxx xxxx xxxx 0111 xxxx : */ | ||
1397 | /* UXTH : cccc 0110 1111 1111 xxxx xxxx 0111 xxxx : */ | ||
1398 | if ((insn & 0x0f8000f0) == 0x06800070) { | ||
1399 | if ((insn & 0x00300000) == 0x00100000) | ||
1400 | return INSN_REJECTED; /* Unallocated space */ | ||
1401 | |||
1402 | if ((insn & 0x000f0000) == 0x000f0000) | ||
1403 | return prep_emulate_rd12rm0(insn, asi); | ||
1404 | else | ||
1405 | return prep_emulate_rd12rn16rm0_wflags(insn, asi); | ||
1406 | } | ||
1407 | |||
1408 | /* Other instruction encodings aren't yet defined */ | ||
1409 | return INSN_REJECTED; | ||
1410 | } | ||
1411 | |||
1412 | static enum kprobe_insn __kprobes | ||
1413 | space_cccc_0111__1(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1414 | { | ||
1415 | /* Undef : cccc 0111 1111 xxxx xxxx xxxx 1111 xxxx */ | ||
1416 | if ((insn & 0x0ff000f0) == 0x03f000f0) | ||
1417 | return INSN_REJECTED; | ||
1418 | |||
1419 | /* SMLALD : cccc 0111 0100 xxxx xxxx xxxx 00x1 xxxx */ | ||
1420 | /* SMLSLD : cccc 0111 0100 xxxx xxxx xxxx 01x1 xxxx */ | ||
1421 | if ((insn & 0x0ff00090) == 0x07400010) | ||
1422 | return prep_emulate_rdhi16rdlo12rs8rm0_wflags(insn, asi); | ||
1423 | |||
1424 | /* SMLAD : cccc 0111 0000 xxxx xxxx xxxx 00x1 xxxx :Q */ | ||
1425 | /* SMUAD : cccc 0111 0000 xxxx 1111 xxxx 00x1 xxxx :Q */ | ||
1426 | /* SMLSD : cccc 0111 0000 xxxx xxxx xxxx 01x1 xxxx :Q */ | ||
1427 | /* SMUSD : cccc 0111 0000 xxxx 1111 xxxx 01x1 xxxx : */ | ||
1428 | /* SMMLA : cccc 0111 0101 xxxx xxxx xxxx 00x1 xxxx : */ | ||
1429 | /* SMMUL : cccc 0111 0101 xxxx 1111 xxxx 00x1 xxxx : */ | ||
1430 | /* USADA8 : cccc 0111 1000 xxxx xxxx xxxx 0001 xxxx : */ | ||
1431 | /* USAD8 : cccc 0111 1000 xxxx 1111 xxxx 0001 xxxx : */ | ||
1432 | if ((insn & 0x0ff00090) == 0x07000010 || | ||
1433 | (insn & 0x0ff000d0) == 0x07500010 || | ||
1434 | (insn & 0x0ff000f0) == 0x07800010) { | ||
1435 | |||
1436 | if ((insn & 0x0000f000) == 0x0000f000) | ||
1437 | return prep_emulate_rd16rs8rm0_wflags(insn, asi); | ||
1438 | else | ||
1439 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1440 | } | ||
1441 | |||
1442 | /* SMMLS : cccc 0111 0101 xxxx xxxx xxxx 11x1 xxxx : */ | ||
1443 | if ((insn & 0x0ff000d0) == 0x075000d0) | ||
1444 | return prep_emulate_rd16rn12rs8rm0_wflags(insn, asi); | ||
1445 | |||
1446 | /* SBFX : cccc 0111 101x xxxx xxxx xxxx x101 xxxx : */ | ||
1447 | /* UBFX : cccc 0111 111x xxxx xxxx xxxx x101 xxxx : */ | ||
1448 | if ((insn & 0x0fa00070) == 0x07a00050) | ||
1449 | return prep_emulate_rd12rm0(insn, asi); | ||
1450 | |||
1451 | /* BFI : cccc 0111 110x xxxx xxxx xxxx x001 xxxx : */ | ||
1452 | /* BFC : cccc 0111 110x xxxx xxxx xxxx x001 1111 : */ | ||
1453 | if ((insn & 0x0fe00070) == 0x07c00010) { | ||
1454 | |||
1455 | if ((insn & 0x0000000f) == 0x0000000f) | ||
1456 | return prep_emulate_rd12_modify(insn, asi); | ||
1457 | else | ||
1458 | return prep_emulate_rd12rn0_modify(insn, asi); | ||
1459 | } | ||
1460 | |||
1461 | return INSN_REJECTED; | ||
1462 | } | ||
1463 | |||
1464 | static enum kprobe_insn __kprobes | ||
1465 | space_cccc_01xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1466 | { | ||
1467 | /* LDR : cccc 01xx x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
1468 | /* LDRB : cccc 01xx x1x1 xxxx xxxx xxxx xxxx xxxx */ | ||
1469 | /* LDRBT : cccc 01x0 x111 xxxx xxxx xxxx xxxx xxxx */ | ||
1470 | /* LDRT : cccc 01x0 x011 xxxx xxxx xxxx xxxx xxxx */ | ||
1471 | /* STR : cccc 01xx x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
1472 | /* STRB : cccc 01xx x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
1473 | /* STRBT : cccc 01x0 x110 xxxx xxxx xxxx xxxx xxxx */ | ||
1474 | /* STRT : cccc 01x0 x010 xxxx xxxx xxxx xxxx xxxx */ | ||
1475 | |||
1476 | if ((insn & 0x00500000) == 0x00500000 && is_r15(insn, 12)) | ||
1477 | return INSN_REJECTED; /* LDRB into PC */ | ||
1478 | |||
1479 | return prep_emulate_ldr_str(insn, asi); | ||
1480 | } | ||
1481 | |||
1482 | static enum kprobe_insn __kprobes | ||
1483 | space_cccc_100x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1484 | { | ||
1485 | /* LDM(2) : cccc 100x x101 xxxx 0xxx xxxx xxxx xxxx */ | ||
1486 | /* LDM(3) : cccc 100x x1x1 xxxx 1xxx xxxx xxxx xxxx */ | ||
1487 | if ((insn & 0x0e708000) == 0x85000000 || | ||
1488 | (insn & 0x0e508000) == 0x85010000) | ||
1489 | return INSN_REJECTED; | ||
1490 | |||
1491 | /* LDM(1) : cccc 100x x0x1 xxxx xxxx xxxx xxxx xxxx */ | ||
1492 | /* STM(1) : cccc 100x x0x0 xxxx xxxx xxxx xxxx xxxx */ | ||
1493 | asi->insn_handler = ((insn & 0x108000) == 0x008000) ? /* STM & R15 */ | ||
1494 | simulate_stm1_pc : simulate_ldm1stm1; | ||
1495 | return INSN_GOOD_NO_SLOT; | ||
1496 | } | ||
1497 | |||
1498 | static enum kprobe_insn __kprobes | ||
1499 | space_cccc_101x(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1500 | { | ||
1501 | /* B : cccc 1010 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1502 | /* BL : cccc 1011 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1503 | asi->insn_handler = simulate_bbl; | ||
1504 | return INSN_GOOD_NO_SLOT; | ||
1505 | } | ||
1506 | |||
1507 | static enum kprobe_insn __kprobes | ||
1508 | space_cccc_11xx(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1509 | { | ||
1510 | /* Coprocessor instructions... */ | ||
1511 | /* MCRR : cccc 1100 0100 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | ||
1512 | /* MRRC : cccc 1100 0101 xxxx xxxx xxxx xxxx xxxx : (Rd!=Rn) */ | ||
1513 | /* LDC : cccc 110x xxx1 xxxx xxxx xxxx xxxx xxxx */ | ||
1514 | /* STC : cccc 110x xxx0 xxxx xxxx xxxx xxxx xxxx */ | ||
1515 | /* CDP : cccc 1110 xxxx xxxx xxxx xxxx xxx0 xxxx */ | ||
1516 | /* MCR : cccc 1110 xxx0 xxxx xxxx xxxx xxx1 xxxx */ | ||
1517 | /* MRC : cccc 1110 xxx1 xxxx xxxx xxxx xxx1 xxxx */ | ||
1518 | |||
1519 | /* SVC : cccc 1111 xxxx xxxx xxxx xxxx xxxx xxxx */ | ||
1520 | |||
1521 | return INSN_REJECTED; | ||
1522 | } | ||
1523 | |||
1524 | static unsigned long __kprobes __check_eq(unsigned long cpsr) | ||
1525 | { | ||
1526 | return cpsr & PSR_Z_BIT; | ||
1527 | } | ||
1528 | |||
1529 | static unsigned long __kprobes __check_ne(unsigned long cpsr) | ||
1530 | { | ||
1531 | return (~cpsr) & PSR_Z_BIT; | ||
1532 | } | ||
1533 | |||
1534 | static unsigned long __kprobes __check_cs(unsigned long cpsr) | ||
1535 | { | ||
1536 | return cpsr & PSR_C_BIT; | ||
1537 | } | ||
1538 | |||
1539 | static unsigned long __kprobes __check_cc(unsigned long cpsr) | ||
1540 | { | ||
1541 | return (~cpsr) & PSR_C_BIT; | ||
1542 | } | ||
1543 | |||
1544 | static unsigned long __kprobes __check_mi(unsigned long cpsr) | ||
1545 | { | ||
1546 | return cpsr & PSR_N_BIT; | ||
1547 | } | ||
1548 | |||
1549 | static unsigned long __kprobes __check_pl(unsigned long cpsr) | ||
1550 | { | ||
1551 | return (~cpsr) & PSR_N_BIT; | ||
1552 | } | ||
1553 | |||
1554 | static unsigned long __kprobes __check_vs(unsigned long cpsr) | ||
1555 | { | ||
1556 | return cpsr & PSR_V_BIT; | ||
1557 | } | ||
1558 | |||
1559 | static unsigned long __kprobes __check_vc(unsigned long cpsr) | ||
1560 | { | ||
1561 | return (~cpsr) & PSR_V_BIT; | ||
1562 | } | ||
1563 | |||
1564 | static unsigned long __kprobes __check_hi(unsigned long cpsr) | ||
1565 | { | ||
1566 | cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ | ||
1567 | return cpsr & PSR_C_BIT; | ||
1568 | } | ||
1569 | |||
1570 | static unsigned long __kprobes __check_ls(unsigned long cpsr) | ||
1571 | { | ||
1572 | cpsr &= ~(cpsr >> 1); /* PSR_C_BIT &= ~PSR_Z_BIT */ | ||
1573 | return (~cpsr) & PSR_C_BIT; | ||
1574 | } | ||
1575 | |||
1576 | static unsigned long __kprobes __check_ge(unsigned long cpsr) | ||
1577 | { | ||
1578 | cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1579 | return (~cpsr) & PSR_N_BIT; | ||
1580 | } | ||
1581 | |||
1582 | static unsigned long __kprobes __check_lt(unsigned long cpsr) | ||
1583 | { | ||
1584 | cpsr ^= (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1585 | return cpsr & PSR_N_BIT; | ||
1586 | } | ||
1587 | |||
1588 | static unsigned long __kprobes __check_gt(unsigned long cpsr) | ||
1589 | { | ||
1590 | unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1591 | temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ | ||
1592 | return (~temp) & PSR_N_BIT; | ||
1593 | } | ||
1594 | |||
1595 | static unsigned long __kprobes __check_le(unsigned long cpsr) | ||
1596 | { | ||
1597 | unsigned long temp = cpsr ^ (cpsr << 3); /* PSR_N_BIT ^= PSR_V_BIT */ | ||
1598 | temp |= (cpsr << 1); /* PSR_N_BIT |= PSR_Z_BIT */ | ||
1599 | return temp & PSR_N_BIT; | ||
1600 | } | ||
1601 | |||
1602 | static unsigned long __kprobes __check_al(unsigned long cpsr) | ||
1603 | { | ||
1604 | return true; | ||
1605 | } | ||
1606 | |||
1607 | static kprobe_check_cc * const condition_checks[16] = { | ||
1608 | &__check_eq, &__check_ne, &__check_cs, &__check_cc, | ||
1609 | &__check_mi, &__check_pl, &__check_vs, &__check_vc, | ||
1610 | &__check_hi, &__check_ls, &__check_ge, &__check_lt, | ||
1611 | &__check_gt, &__check_le, &__check_al, &__check_al | ||
1612 | }; | ||
1613 | |||
1614 | /* Return: | ||
1615 | * INSN_REJECTED If instruction is one not allowed to kprobe, | ||
1616 | * INSN_GOOD If instruction is supported and uses instruction slot, | ||
1617 | * INSN_GOOD_NO_SLOT If instruction is supported but doesn't use its slot. | ||
1618 | * | ||
1619 | * For instructions we don't want to kprobe (INSN_REJECTED return result): | ||
1620 | * These are generally ones that modify the processor state making | ||
1621 | * them "hard" to simulate such as switches processor modes or | ||
1622 | * make accesses in alternate modes. Any of these could be simulated | ||
1623 | * if the work was put into it, but low return considering they | ||
1624 | * should also be very rare. | ||
1625 | */ | ||
1626 | enum kprobe_insn __kprobes | ||
1627 | arm_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1628 | { | ||
1629 | asi->insn_check_cc = condition_checks[insn>>28]; | ||
1630 | asi->insn[1] = KPROBE_RETURN_INSTRUCTION; | ||
1631 | |||
1632 | if ((insn & 0xf0000000) == 0xf0000000) | ||
1633 | |||
1634 | return space_1111(insn, asi); | ||
1635 | |||
1636 | else if ((insn & 0x0e000000) == 0x00000000) | ||
1637 | |||
1638 | return space_cccc_000x(insn, asi); | ||
1639 | |||
1640 | else if ((insn & 0x0e000000) == 0x02000000) | ||
1641 | |||
1642 | return space_cccc_001x(insn, asi); | ||
1643 | |||
1644 | else if ((insn & 0x0f000010) == 0x06000010) | ||
1645 | |||
1646 | return space_cccc_0110__1(insn, asi); | ||
1647 | |||
1648 | else if ((insn & 0x0f000010) == 0x07000010) | ||
1649 | |||
1650 | return space_cccc_0111__1(insn, asi); | ||
1651 | |||
1652 | else if ((insn & 0x0c000000) == 0x04000000) | ||
1653 | |||
1654 | return space_cccc_01xx(insn, asi); | ||
1655 | |||
1656 | else if ((insn & 0x0e000000) == 0x08000000) | ||
1657 | |||
1658 | return space_cccc_100x(insn, asi); | ||
1659 | |||
1660 | else if ((insn & 0x0e000000) == 0x0a000000) | ||
1661 | |||
1662 | return space_cccc_101x(insn, asi); | ||
1663 | |||
1664 | return space_cccc_11xx(insn, asi); | ||
1665 | } | ||
1666 | |||
1667 | void __init arm_kprobe_decode_init(void) | ||
1668 | { | ||
1669 | find_str_pc_offset(); | ||
1670 | } | ||
diff --git a/arch/arm/kernel/kprobes-thumb.c b/arch/arm/kernel/kprobes-thumb.c new file mode 100644 index 000000000000..902ca59e8b11 --- /dev/null +++ b/arch/arm/kernel/kprobes-thumb.c | |||
@@ -0,0 +1,1462 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/kprobes-thumb.c | ||
3 | * | ||
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License version 2 as | ||
8 | * published by the Free Software Foundation. | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <linux/kprobes.h> | ||
13 | |||
14 | #include "kprobes.h" | ||
15 | |||
16 | |||
17 | /* | ||
18 | * True if current instruction is in an IT block. | ||
19 | */ | ||
20 | #define in_it_block(cpsr) ((cpsr & 0x06000c00) != 0x00000000) | ||
21 | |||
22 | /* | ||
23 | * Return the condition code to check for the currently executing instruction. | ||
24 | * This is in ITSTATE<7:4> which is in CPSR<15:12> but is only valid if | ||
25 | * in_it_block returns true. | ||
26 | */ | ||
27 | #define current_cond(cpsr) ((cpsr >> 12) & 0xf) | ||
28 | |||
29 | /* | ||
30 | * Return the PC value for a probe in thumb code. | ||
31 | * This is the address of the probed instruction plus 4. | ||
32 | * We subtract one because the address will have bit zero set to indicate | ||
33 | * a pointer to thumb code. | ||
34 | */ | ||
35 | static inline unsigned long __kprobes thumb_probe_pc(struct kprobe *p) | ||
36 | { | ||
37 | return (unsigned long)p->addr - 1 + 4; | ||
38 | } | ||
39 | |||
40 | static void __kprobes | ||
41 | t32_simulate_table_branch(struct kprobe *p, struct pt_regs *regs) | ||
42 | { | ||
43 | kprobe_opcode_t insn = p->opcode; | ||
44 | unsigned long pc = thumb_probe_pc(p); | ||
45 | int rn = (insn >> 16) & 0xf; | ||
46 | int rm = insn & 0xf; | ||
47 | |||
48 | unsigned long rnv = (rn == 15) ? pc : regs->uregs[rn]; | ||
49 | unsigned long rmv = regs->uregs[rm]; | ||
50 | unsigned int halfwords; | ||
51 | |||
52 | if (insn & 0x10) /* TBH */ | ||
53 | halfwords = ((u16 *)rnv)[rmv]; | ||
54 | else /* TBB */ | ||
55 | halfwords = ((u8 *)rnv)[rmv]; | ||
56 | |||
57 | regs->ARM_pc = pc + 2 * halfwords; | ||
58 | } | ||
59 | |||
60 | static void __kprobes | ||
61 | t32_simulate_mrs(struct kprobe *p, struct pt_regs *regs) | ||
62 | { | ||
63 | kprobe_opcode_t insn = p->opcode; | ||
64 | int rd = (insn >> 8) & 0xf; | ||
65 | unsigned long mask = 0xf8ff03df; /* Mask out execution state */ | ||
66 | regs->uregs[rd] = regs->ARM_cpsr & mask; | ||
67 | } | ||
68 | |||
69 | static void __kprobes | ||
70 | t32_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) | ||
71 | { | ||
72 | kprobe_opcode_t insn = p->opcode; | ||
73 | unsigned long pc = thumb_probe_pc(p); | ||
74 | |||
75 | long offset = insn & 0x7ff; /* imm11 */ | ||
76 | offset += (insn & 0x003f0000) >> 5; /* imm6 */ | ||
77 | offset += (insn & 0x00002000) << 4; /* J1 */ | ||
78 | offset += (insn & 0x00000800) << 7; /* J2 */ | ||
79 | offset -= (insn & 0x04000000) >> 7; /* Apply sign bit */ | ||
80 | |||
81 | regs->ARM_pc = pc + (offset * 2); | ||
82 | } | ||
83 | |||
84 | static enum kprobe_insn __kprobes | ||
85 | t32_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
86 | { | ||
87 | int cc = (insn >> 22) & 0xf; | ||
88 | asi->insn_check_cc = kprobe_condition_checks[cc]; | ||
89 | asi->insn_handler = t32_simulate_cond_branch; | ||
90 | return INSN_GOOD_NO_SLOT; | ||
91 | } | ||
92 | |||
93 | static void __kprobes | ||
94 | t32_simulate_branch(struct kprobe *p, struct pt_regs *regs) | ||
95 | { | ||
96 | kprobe_opcode_t insn = p->opcode; | ||
97 | unsigned long pc = thumb_probe_pc(p); | ||
98 | |||
99 | long offset = insn & 0x7ff; /* imm11 */ | ||
100 | offset += (insn & 0x03ff0000) >> 5; /* imm10 */ | ||
101 | offset += (insn & 0x00002000) << 9; /* J1 */ | ||
102 | offset += (insn & 0x00000800) << 10; /* J2 */ | ||
103 | if (insn & 0x04000000) | ||
104 | offset -= 0x00800000; /* Apply sign bit */ | ||
105 | else | ||
106 | offset ^= 0x00600000; /* Invert J1 and J2 */ | ||
107 | |||
108 | if (insn & (1 << 14)) { | ||
109 | /* BL or BLX */ | ||
110 | regs->ARM_lr = (unsigned long)p->addr + 4; | ||
111 | if (!(insn & (1 << 12))) { | ||
112 | /* BLX so switch to ARM mode */ | ||
113 | regs->ARM_cpsr &= ~PSR_T_BIT; | ||
114 | pc &= ~3; | ||
115 | } | ||
116 | } | ||
117 | |||
118 | regs->ARM_pc = pc + (offset * 2); | ||
119 | } | ||
120 | |||
121 | static void __kprobes | ||
122 | t32_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) | ||
123 | { | ||
124 | kprobe_opcode_t insn = p->opcode; | ||
125 | unsigned long addr = thumb_probe_pc(p) & ~3; | ||
126 | int rt = (insn >> 12) & 0xf; | ||
127 | unsigned long rtv; | ||
128 | |||
129 | long offset = insn & 0xfff; | ||
130 | if (insn & 0x00800000) | ||
131 | addr += offset; | ||
132 | else | ||
133 | addr -= offset; | ||
134 | |||
135 | if (insn & 0x00400000) { | ||
136 | /* LDR */ | ||
137 | rtv = *(unsigned long *)addr; | ||
138 | if (rt == 15) { | ||
139 | bx_write_pc(rtv, regs); | ||
140 | return; | ||
141 | } | ||
142 | } else if (insn & 0x00200000) { | ||
143 | /* LDRH */ | ||
144 | if (insn & 0x01000000) | ||
145 | rtv = *(s16 *)addr; | ||
146 | else | ||
147 | rtv = *(u16 *)addr; | ||
148 | } else { | ||
149 | /* LDRB */ | ||
150 | if (insn & 0x01000000) | ||
151 | rtv = *(s8 *)addr; | ||
152 | else | ||
153 | rtv = *(u8 *)addr; | ||
154 | } | ||
155 | |||
156 | regs->uregs[rt] = rtv; | ||
157 | } | ||
158 | |||
159 | static enum kprobe_insn __kprobes | ||
160 | t32_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
161 | { | ||
162 | enum kprobe_insn ret = kprobe_decode_ldmstm(insn, asi); | ||
163 | |||
164 | /* Fixup modified instruction to have halfwords in correct order...*/ | ||
165 | insn = asi->insn[0]; | ||
166 | ((u16 *)asi->insn)[0] = insn >> 16; | ||
167 | ((u16 *)asi->insn)[1] = insn & 0xffff; | ||
168 | |||
169 | return ret; | ||
170 | } | ||
171 | |||
172 | static void __kprobes | ||
173 | t32_emulate_ldrdstrd(struct kprobe *p, struct pt_regs *regs) | ||
174 | { | ||
175 | kprobe_opcode_t insn = p->opcode; | ||
176 | unsigned long pc = thumb_probe_pc(p) & ~3; | ||
177 | int rt1 = (insn >> 12) & 0xf; | ||
178 | int rt2 = (insn >> 8) & 0xf; | ||
179 | int rn = (insn >> 16) & 0xf; | ||
180 | |||
181 | register unsigned long rt1v asm("r0") = regs->uregs[rt1]; | ||
182 | register unsigned long rt2v asm("r1") = regs->uregs[rt2]; | ||
183 | register unsigned long rnv asm("r2") = (rn == 15) ? pc | ||
184 | : regs->uregs[rn]; | ||
185 | |||
186 | __asm__ __volatile__ ( | ||
187 | "blx %[fn]" | ||
188 | : "=r" (rt1v), "=r" (rt2v), "=r" (rnv) | ||
189 | : "0" (rt1v), "1" (rt2v), "2" (rnv), [fn] "r" (p->ainsn.insn_fn) | ||
190 | : "lr", "memory", "cc" | ||
191 | ); | ||
192 | |||
193 | if (rn != 15) | ||
194 | regs->uregs[rn] = rnv; /* Writeback base register */ | ||
195 | regs->uregs[rt1] = rt1v; | ||
196 | regs->uregs[rt2] = rt2v; | ||
197 | } | ||
198 | |||
199 | static void __kprobes | ||
200 | t32_emulate_ldrstr(struct kprobe *p, struct pt_regs *regs) | ||
201 | { | ||
202 | kprobe_opcode_t insn = p->opcode; | ||
203 | int rt = (insn >> 12) & 0xf; | ||
204 | int rn = (insn >> 16) & 0xf; | ||
205 | int rm = insn & 0xf; | ||
206 | |||
207 | register unsigned long rtv asm("r0") = regs->uregs[rt]; | ||
208 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
209 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
210 | |||
211 | __asm__ __volatile__ ( | ||
212 | "blx %[fn]" | ||
213 | : "=r" (rtv), "=r" (rnv) | ||
214 | : "0" (rtv), "1" (rnv), "r" (rmv), [fn] "r" (p->ainsn.insn_fn) | ||
215 | : "lr", "memory", "cc" | ||
216 | ); | ||
217 | |||
218 | regs->uregs[rn] = rnv; /* Writeback base register */ | ||
219 | if (rt == 15) /* Can't be true for a STR as they aren't allowed */ | ||
220 | bx_write_pc(rtv, regs); | ||
221 | else | ||
222 | regs->uregs[rt] = rtv; | ||
223 | } | ||
224 | |||
225 | static void __kprobes | ||
226 | t32_emulate_rd8rn16rm0_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
227 | { | ||
228 | kprobe_opcode_t insn = p->opcode; | ||
229 | int rd = (insn >> 8) & 0xf; | ||
230 | int rn = (insn >> 16) & 0xf; | ||
231 | int rm = insn & 0xf; | ||
232 | |||
233 | register unsigned long rdv asm("r1") = regs->uregs[rd]; | ||
234 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
235 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
236 | unsigned long cpsr = regs->ARM_cpsr; | ||
237 | |||
238 | __asm__ __volatile__ ( | ||
239 | "msr cpsr_fs, %[cpsr] \n\t" | ||
240 | "blx %[fn] \n\t" | ||
241 | "mrs %[cpsr], cpsr \n\t" | ||
242 | : "=r" (rdv), [cpsr] "=r" (cpsr) | ||
243 | : "0" (rdv), "r" (rnv), "r" (rmv), | ||
244 | "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
245 | : "lr", "memory", "cc" | ||
246 | ); | ||
247 | |||
248 | regs->uregs[rd] = rdv; | ||
249 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
250 | } | ||
251 | |||
252 | static void __kprobes | ||
253 | t32_emulate_rd8pc16_noflags(struct kprobe *p, struct pt_regs *regs) | ||
254 | { | ||
255 | kprobe_opcode_t insn = p->opcode; | ||
256 | unsigned long pc = thumb_probe_pc(p); | ||
257 | int rd = (insn >> 8) & 0xf; | ||
258 | |||
259 | register unsigned long rdv asm("r1") = regs->uregs[rd]; | ||
260 | register unsigned long rnv asm("r2") = pc & ~3; | ||
261 | |||
262 | __asm__ __volatile__ ( | ||
263 | "blx %[fn]" | ||
264 | : "=r" (rdv) | ||
265 | : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) | ||
266 | : "lr", "memory", "cc" | ||
267 | ); | ||
268 | |||
269 | regs->uregs[rd] = rdv; | ||
270 | } | ||
271 | |||
272 | static void __kprobes | ||
273 | t32_emulate_rd8rn16_noflags(struct kprobe *p, struct pt_regs *regs) | ||
274 | { | ||
275 | kprobe_opcode_t insn = p->opcode; | ||
276 | int rd = (insn >> 8) & 0xf; | ||
277 | int rn = (insn >> 16) & 0xf; | ||
278 | |||
279 | register unsigned long rdv asm("r1") = regs->uregs[rd]; | ||
280 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
281 | |||
282 | __asm__ __volatile__ ( | ||
283 | "blx %[fn]" | ||
284 | : "=r" (rdv) | ||
285 | : "0" (rdv), "r" (rnv), [fn] "r" (p->ainsn.insn_fn) | ||
286 | : "lr", "memory", "cc" | ||
287 | ); | ||
288 | |||
289 | regs->uregs[rd] = rdv; | ||
290 | } | ||
291 | |||
292 | static void __kprobes | ||
293 | t32_emulate_rdlo12rdhi8rn16rm0_noflags(struct kprobe *p, struct pt_regs *regs) | ||
294 | { | ||
295 | kprobe_opcode_t insn = p->opcode; | ||
296 | int rdlo = (insn >> 12) & 0xf; | ||
297 | int rdhi = (insn >> 8) & 0xf; | ||
298 | int rn = (insn >> 16) & 0xf; | ||
299 | int rm = insn & 0xf; | ||
300 | |||
301 | register unsigned long rdlov asm("r0") = regs->uregs[rdlo]; | ||
302 | register unsigned long rdhiv asm("r1") = regs->uregs[rdhi]; | ||
303 | register unsigned long rnv asm("r2") = regs->uregs[rn]; | ||
304 | register unsigned long rmv asm("r3") = regs->uregs[rm]; | ||
305 | |||
306 | __asm__ __volatile__ ( | ||
307 | "blx %[fn]" | ||
308 | : "=r" (rdlov), "=r" (rdhiv) | ||
309 | : "0" (rdlov), "1" (rdhiv), "r" (rnv), "r" (rmv), | ||
310 | [fn] "r" (p->ainsn.insn_fn) | ||
311 | : "lr", "memory", "cc" | ||
312 | ); | ||
313 | |||
314 | regs->uregs[rdlo] = rdlov; | ||
315 | regs->uregs[rdhi] = rdhiv; | ||
316 | } | ||
317 | |||
318 | /* These emulation encodings are functionally equivalent... */ | ||
319 | #define t32_emulate_rd8rn16rm0ra12_noflags \ | ||
320 | t32_emulate_rdlo12rdhi8rn16rm0_noflags | ||
321 | |||
322 | static const union decode_item t32_table_1110_100x_x0xx[] = { | ||
323 | /* Load/store multiple instructions */ | ||
324 | |||
325 | /* Rn is PC 1110 100x x0xx 1111 xxxx xxxx xxxx xxxx */ | ||
326 | DECODE_REJECT (0xfe4f0000, 0xe80f0000), | ||
327 | |||
328 | /* SRS 1110 1000 00x0 xxxx xxxx xxxx xxxx xxxx */ | ||
329 | /* RFE 1110 1000 00x1 xxxx xxxx xxxx xxxx xxxx */ | ||
330 | DECODE_REJECT (0xffc00000, 0xe8000000), | ||
331 | /* SRS 1110 1001 10x0 xxxx xxxx xxxx xxxx xxxx */ | ||
332 | /* RFE 1110 1001 10x1 xxxx xxxx xxxx xxxx xxxx */ | ||
333 | DECODE_REJECT (0xffc00000, 0xe9800000), | ||
334 | |||
335 | /* STM Rn, {...pc} 1110 100x x0x0 xxxx 1xxx xxxx xxxx xxxx */ | ||
336 | DECODE_REJECT (0xfe508000, 0xe8008000), | ||
337 | /* LDM Rn, {...lr,pc} 1110 100x x0x1 xxxx 11xx xxxx xxxx xxxx */ | ||
338 | DECODE_REJECT (0xfe50c000, 0xe810c000), | ||
339 | /* LDM/STM Rn, {...sp} 1110 100x x0xx xxxx xx1x xxxx xxxx xxxx */ | ||
340 | DECODE_REJECT (0xfe402000, 0xe8002000), | ||
341 | |||
342 | /* STMIA 1110 1000 10x0 xxxx xxxx xxxx xxxx xxxx */ | ||
343 | /* LDMIA 1110 1000 10x1 xxxx xxxx xxxx xxxx xxxx */ | ||
344 | /* STMDB 1110 1001 00x0 xxxx xxxx xxxx xxxx xxxx */ | ||
345 | /* LDMDB 1110 1001 00x1 xxxx xxxx xxxx xxxx xxxx */ | ||
346 | DECODE_CUSTOM (0xfe400000, 0xe8000000, t32_decode_ldmstm), | ||
347 | |||
348 | DECODE_END | ||
349 | }; | ||
350 | |||
351 | static const union decode_item t32_table_1110_100x_x1xx[] = { | ||
352 | /* Load/store dual, load/store exclusive, table branch */ | ||
353 | |||
354 | /* STRD (immediate) 1110 1000 x110 xxxx xxxx xxxx xxxx xxxx */ | ||
355 | /* LDRD (immediate) 1110 1000 x111 xxxx xxxx xxxx xxxx xxxx */ | ||
356 | DECODE_OR (0xff600000, 0xe8600000), | ||
357 | /* STRD (immediate) 1110 1001 x1x0 xxxx xxxx xxxx xxxx xxxx */ | ||
358 | /* LDRD (immediate) 1110 1001 x1x1 xxxx xxxx xxxx xxxx xxxx */ | ||
359 | DECODE_EMULATEX (0xff400000, 0xe9400000, t32_emulate_ldrdstrd, | ||
360 | REGS(NOPCWB, NOSPPC, NOSPPC, 0, 0)), | ||
361 | |||
362 | /* TBB 1110 1000 1101 xxxx xxxx xxxx 0000 xxxx */ | ||
363 | /* TBH 1110 1000 1101 xxxx xxxx xxxx 0001 xxxx */ | ||
364 | DECODE_SIMULATEX(0xfff000e0, 0xe8d00000, t32_simulate_table_branch, | ||
365 | REGS(NOSP, 0, 0, 0, NOSPPC)), | ||
366 | |||
367 | /* STREX 1110 1000 0100 xxxx xxxx xxxx xxxx xxxx */ | ||
368 | /* LDREX 1110 1000 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
369 | /* STREXB 1110 1000 1100 xxxx xxxx xxxx 0100 xxxx */ | ||
370 | /* STREXH 1110 1000 1100 xxxx xxxx xxxx 0101 xxxx */ | ||
371 | /* STREXD 1110 1000 1100 xxxx xxxx xxxx 0111 xxxx */ | ||
372 | /* LDREXB 1110 1000 1101 xxxx xxxx xxxx 0100 xxxx */ | ||
373 | /* LDREXH 1110 1000 1101 xxxx xxxx xxxx 0101 xxxx */ | ||
374 | /* LDREXD 1110 1000 1101 xxxx xxxx xxxx 0111 xxxx */ | ||
375 | /* And unallocated instructions... */ | ||
376 | DECODE_END | ||
377 | }; | ||
378 | |||
379 | static const union decode_item t32_table_1110_101x[] = { | ||
380 | /* Data-processing (shifted register) */ | ||
381 | |||
382 | /* TST 1110 1010 0001 xxxx xxxx 1111 xxxx xxxx */ | ||
383 | /* TEQ 1110 1010 1001 xxxx xxxx 1111 xxxx xxxx */ | ||
384 | DECODE_EMULATEX (0xff700f00, 0xea100f00, t32_emulate_rd8rn16rm0_rwflags, | ||
385 | REGS(NOSPPC, 0, 0, 0, NOSPPC)), | ||
386 | |||
387 | /* CMN 1110 1011 0001 xxxx xxxx 1111 xxxx xxxx */ | ||
388 | DECODE_OR (0xfff00f00, 0xeb100f00), | ||
389 | /* CMP 1110 1011 1011 xxxx xxxx 1111 xxxx xxxx */ | ||
390 | DECODE_EMULATEX (0xfff00f00, 0xebb00f00, t32_emulate_rd8rn16rm0_rwflags, | ||
391 | REGS(NOPC, 0, 0, 0, NOSPPC)), | ||
392 | |||
393 | /* MOV 1110 1010 010x 1111 xxxx xxxx xxxx xxxx */ | ||
394 | /* MVN 1110 1010 011x 1111 xxxx xxxx xxxx xxxx */ | ||
395 | DECODE_EMULATEX (0xffcf0000, 0xea4f0000, t32_emulate_rd8rn16rm0_rwflags, | ||
396 | REGS(0, 0, NOSPPC, 0, NOSPPC)), | ||
397 | |||
398 | /* ??? 1110 1010 101x xxxx xxxx xxxx xxxx xxxx */ | ||
399 | /* ??? 1110 1010 111x xxxx xxxx xxxx xxxx xxxx */ | ||
400 | DECODE_REJECT (0xffa00000, 0xeaa00000), | ||
401 | /* ??? 1110 1011 001x xxxx xxxx xxxx xxxx xxxx */ | ||
402 | DECODE_REJECT (0xffe00000, 0xeb200000), | ||
403 | /* ??? 1110 1011 100x xxxx xxxx xxxx xxxx xxxx */ | ||
404 | DECODE_REJECT (0xffe00000, 0xeb800000), | ||
405 | /* ??? 1110 1011 111x xxxx xxxx xxxx xxxx xxxx */ | ||
406 | DECODE_REJECT (0xffe00000, 0xebe00000), | ||
407 | |||
408 | /* ADD/SUB SP, SP, Rm, LSL #0..3 */ | ||
409 | /* 1110 1011 x0xx 1101 x000 1101 xx00 xxxx */ | ||
410 | DECODE_EMULATEX (0xff4f7f30, 0xeb0d0d00, t32_emulate_rd8rn16rm0_rwflags, | ||
411 | REGS(SP, 0, SP, 0, NOSPPC)), | ||
412 | |||
413 | /* ADD/SUB SP, SP, Rm, shift */ | ||
414 | /* 1110 1011 x0xx 1101 xxxx 1101 xxxx xxxx */ | ||
415 | DECODE_REJECT (0xff4f0f00, 0xeb0d0d00), | ||
416 | |||
417 | /* ADD/SUB Rd, SP, Rm, shift */ | ||
418 | /* 1110 1011 x0xx 1101 xxxx xxxx xxxx xxxx */ | ||
419 | DECODE_EMULATEX (0xff4f0000, 0xeb0d0000, t32_emulate_rd8rn16rm0_rwflags, | ||
420 | REGS(SP, 0, NOPC, 0, NOSPPC)), | ||
421 | |||
422 | /* AND 1110 1010 000x xxxx xxxx xxxx xxxx xxxx */ | ||
423 | /* BIC 1110 1010 001x xxxx xxxx xxxx xxxx xxxx */ | ||
424 | /* ORR 1110 1010 010x xxxx xxxx xxxx xxxx xxxx */ | ||
425 | /* ORN 1110 1010 011x xxxx xxxx xxxx xxxx xxxx */ | ||
426 | /* EOR 1110 1010 100x xxxx xxxx xxxx xxxx xxxx */ | ||
427 | /* PKH 1110 1010 110x xxxx xxxx xxxx xxxx xxxx */ | ||
428 | /* ADD 1110 1011 000x xxxx xxxx xxxx xxxx xxxx */ | ||
429 | /* ADC 1110 1011 010x xxxx xxxx xxxx xxxx xxxx */ | ||
430 | /* SBC 1110 1011 011x xxxx xxxx xxxx xxxx xxxx */ | ||
431 | /* SUB 1110 1011 101x xxxx xxxx xxxx xxxx xxxx */ | ||
432 | /* RSB 1110 1011 110x xxxx xxxx xxxx xxxx xxxx */ | ||
433 | DECODE_EMULATEX (0xfe000000, 0xea000000, t32_emulate_rd8rn16rm0_rwflags, | ||
434 | REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), | ||
435 | |||
436 | DECODE_END | ||
437 | }; | ||
438 | |||
439 | static const union decode_item t32_table_1111_0x0x___0[] = { | ||
440 | /* Data-processing (modified immediate) */ | ||
441 | |||
442 | /* TST 1111 0x00 0001 xxxx 0xxx 1111 xxxx xxxx */ | ||
443 | /* TEQ 1111 0x00 1001 xxxx 0xxx 1111 xxxx xxxx */ | ||
444 | DECODE_EMULATEX (0xfb708f00, 0xf0100f00, t32_emulate_rd8rn16rm0_rwflags, | ||
445 | REGS(NOSPPC, 0, 0, 0, 0)), | ||
446 | |||
447 | /* CMN 1111 0x01 0001 xxxx 0xxx 1111 xxxx xxxx */ | ||
448 | DECODE_OR (0xfbf08f00, 0xf1100f00), | ||
449 | /* CMP 1111 0x01 1011 xxxx 0xxx 1111 xxxx xxxx */ | ||
450 | DECODE_EMULATEX (0xfbf08f00, 0xf1b00f00, t32_emulate_rd8rn16rm0_rwflags, | ||
451 | REGS(NOPC, 0, 0, 0, 0)), | ||
452 | |||
453 | /* MOV 1111 0x00 010x 1111 0xxx xxxx xxxx xxxx */ | ||
454 | /* MVN 1111 0x00 011x 1111 0xxx xxxx xxxx xxxx */ | ||
455 | DECODE_EMULATEX (0xfbcf8000, 0xf04f0000, t32_emulate_rd8rn16rm0_rwflags, | ||
456 | REGS(0, 0, NOSPPC, 0, 0)), | ||
457 | |||
458 | /* ??? 1111 0x00 101x xxxx 0xxx xxxx xxxx xxxx */ | ||
459 | DECODE_REJECT (0xfbe08000, 0xf0a00000), | ||
460 | /* ??? 1111 0x00 110x xxxx 0xxx xxxx xxxx xxxx */ | ||
461 | /* ??? 1111 0x00 111x xxxx 0xxx xxxx xxxx xxxx */ | ||
462 | DECODE_REJECT (0xfbc08000, 0xf0c00000), | ||
463 | /* ??? 1111 0x01 001x xxxx 0xxx xxxx xxxx xxxx */ | ||
464 | DECODE_REJECT (0xfbe08000, 0xf1200000), | ||
465 | /* ??? 1111 0x01 100x xxxx 0xxx xxxx xxxx xxxx */ | ||
466 | DECODE_REJECT (0xfbe08000, 0xf1800000), | ||
467 | /* ??? 1111 0x01 111x xxxx 0xxx xxxx xxxx xxxx */ | ||
468 | DECODE_REJECT (0xfbe08000, 0xf1e00000), | ||
469 | |||
470 | /* ADD Rd, SP, #imm 1111 0x01 000x 1101 0xxx xxxx xxxx xxxx */ | ||
471 | /* SUB Rd, SP, #imm 1111 0x01 101x 1101 0xxx xxxx xxxx xxxx */ | ||
472 | DECODE_EMULATEX (0xfb4f8000, 0xf10d0000, t32_emulate_rd8rn16rm0_rwflags, | ||
473 | REGS(SP, 0, NOPC, 0, 0)), | ||
474 | |||
475 | /* AND 1111 0x00 000x xxxx 0xxx xxxx xxxx xxxx */ | ||
476 | /* BIC 1111 0x00 001x xxxx 0xxx xxxx xxxx xxxx */ | ||
477 | /* ORR 1111 0x00 010x xxxx 0xxx xxxx xxxx xxxx */ | ||
478 | /* ORN 1111 0x00 011x xxxx 0xxx xxxx xxxx xxxx */ | ||
479 | /* EOR 1111 0x00 100x xxxx 0xxx xxxx xxxx xxxx */ | ||
480 | /* ADD 1111 0x01 000x xxxx 0xxx xxxx xxxx xxxx */ | ||
481 | /* ADC 1111 0x01 010x xxxx 0xxx xxxx xxxx xxxx */ | ||
482 | /* SBC 1111 0x01 011x xxxx 0xxx xxxx xxxx xxxx */ | ||
483 | /* SUB 1111 0x01 101x xxxx 0xxx xxxx xxxx xxxx */ | ||
484 | /* RSB 1111 0x01 110x xxxx 0xxx xxxx xxxx xxxx */ | ||
485 | DECODE_EMULATEX (0xfa008000, 0xf0000000, t32_emulate_rd8rn16rm0_rwflags, | ||
486 | REGS(NOSPPC, 0, NOSPPC, 0, 0)), | ||
487 | |||
488 | DECODE_END | ||
489 | }; | ||
490 | |||
491 | static const union decode_item t32_table_1111_0x1x___0[] = { | ||
492 | /* Data-processing (plain binary immediate) */ | ||
493 | |||
494 | /* ADDW Rd, PC, #imm 1111 0x10 0000 1111 0xxx xxxx xxxx xxxx */ | ||
495 | DECODE_OR (0xfbff8000, 0xf20f0000), | ||
496 | /* SUBW Rd, PC, #imm 1111 0x10 1010 1111 0xxx xxxx xxxx xxxx */ | ||
497 | DECODE_EMULATEX (0xfbff8000, 0xf2af0000, t32_emulate_rd8pc16_noflags, | ||
498 | REGS(PC, 0, NOSPPC, 0, 0)), | ||
499 | |||
500 | /* ADDW SP, SP, #imm 1111 0x10 0000 1101 0xxx 1101 xxxx xxxx */ | ||
501 | DECODE_OR (0xfbff8f00, 0xf20d0d00), | ||
502 | /* SUBW SP, SP, #imm 1111 0x10 1010 1101 0xxx 1101 xxxx xxxx */ | ||
503 | DECODE_EMULATEX (0xfbff8f00, 0xf2ad0d00, t32_emulate_rd8rn16_noflags, | ||
504 | REGS(SP, 0, SP, 0, 0)), | ||
505 | |||
506 | /* ADDW 1111 0x10 0000 xxxx 0xxx xxxx xxxx xxxx */ | ||
507 | DECODE_OR (0xfbf08000, 0xf2000000), | ||
508 | /* SUBW 1111 0x10 1010 xxxx 0xxx xxxx xxxx xxxx */ | ||
509 | DECODE_EMULATEX (0xfbf08000, 0xf2a00000, t32_emulate_rd8rn16_noflags, | ||
510 | REGS(NOPCX, 0, NOSPPC, 0, 0)), | ||
511 | |||
512 | /* MOVW 1111 0x10 0100 xxxx 0xxx xxxx xxxx xxxx */ | ||
513 | /* MOVT 1111 0x10 1100 xxxx 0xxx xxxx xxxx xxxx */ | ||
514 | DECODE_EMULATEX (0xfb708000, 0xf2400000, t32_emulate_rd8rn16_noflags, | ||
515 | REGS(0, 0, NOSPPC, 0, 0)), | ||
516 | |||
517 | /* SSAT16 1111 0x11 0010 xxxx 0000 xxxx 00xx xxxx */ | ||
518 | /* SSAT 1111 0x11 00x0 xxxx 0xxx xxxx xxxx xxxx */ | ||
519 | /* USAT16 1111 0x11 1010 xxxx 0000 xxxx 00xx xxxx */ | ||
520 | /* USAT 1111 0x11 10x0 xxxx 0xxx xxxx xxxx xxxx */ | ||
521 | DECODE_EMULATEX (0xfb508000, 0xf3000000, t32_emulate_rd8rn16rm0_rwflags, | ||
522 | REGS(NOSPPC, 0, NOSPPC, 0, 0)), | ||
523 | |||
524 | /* SFBX 1111 0x11 0100 xxxx 0xxx xxxx xxxx xxxx */ | ||
525 | /* UFBX 1111 0x11 1100 xxxx 0xxx xxxx xxxx xxxx */ | ||
526 | DECODE_EMULATEX (0xfb708000, 0xf3400000, t32_emulate_rd8rn16_noflags, | ||
527 | REGS(NOSPPC, 0, NOSPPC, 0, 0)), | ||
528 | |||
529 | /* BFC 1111 0x11 0110 1111 0xxx xxxx xxxx xxxx */ | ||
530 | DECODE_EMULATEX (0xfbff8000, 0xf36f0000, t32_emulate_rd8rn16_noflags, | ||
531 | REGS(0, 0, NOSPPC, 0, 0)), | ||
532 | |||
533 | /* BFI 1111 0x11 0110 xxxx 0xxx xxxx xxxx xxxx */ | ||
534 | DECODE_EMULATEX (0xfbf08000, 0xf3600000, t32_emulate_rd8rn16_noflags, | ||
535 | REGS(NOSPPCX, 0, NOSPPC, 0, 0)), | ||
536 | |||
537 | DECODE_END | ||
538 | }; | ||
539 | |||
540 | static const union decode_item t32_table_1111_0xxx___1[] = { | ||
541 | /* Branches and miscellaneous control */ | ||
542 | |||
543 | /* YIELD 1111 0011 1010 xxxx 10x0 x000 0000 0001 */ | ||
544 | DECODE_OR (0xfff0d7ff, 0xf3a08001), | ||
545 | /* SEV 1111 0011 1010 xxxx 10x0 x000 0000 0100 */ | ||
546 | DECODE_EMULATE (0xfff0d7ff, 0xf3a08004, kprobe_emulate_none), | ||
547 | /* NOP 1111 0011 1010 xxxx 10x0 x000 0000 0000 */ | ||
548 | /* WFE 1111 0011 1010 xxxx 10x0 x000 0000 0010 */ | ||
549 | /* WFI 1111 0011 1010 xxxx 10x0 x000 0000 0011 */ | ||
550 | DECODE_SIMULATE (0xfff0d7fc, 0xf3a08000, kprobe_simulate_nop), | ||
551 | |||
552 | /* MRS Rd, CPSR 1111 0011 1110 xxxx 10x0 xxxx xxxx xxxx */ | ||
553 | DECODE_SIMULATEX(0xfff0d000, 0xf3e08000, t32_simulate_mrs, | ||
554 | REGS(0, 0, NOSPPC, 0, 0)), | ||
555 | |||
556 | /* | ||
557 | * Unsupported instructions | ||
558 | * 1111 0x11 1xxx xxxx 10x0 xxxx xxxx xxxx | ||
559 | * | ||
560 | * MSR 1111 0011 100x xxxx 10x0 xxxx xxxx xxxx | ||
561 | * DBG hint 1111 0011 1010 xxxx 10x0 x000 1111 xxxx | ||
562 | * Unallocated hints 1111 0011 1010 xxxx 10x0 x000 xxxx xxxx | ||
563 | * CPS 1111 0011 1010 xxxx 10x0 xxxx xxxx xxxx | ||
564 | * CLREX/DSB/DMB/ISB 1111 0011 1011 xxxx 10x0 xxxx xxxx xxxx | ||
565 | * BXJ 1111 0011 1100 xxxx 10x0 xxxx xxxx xxxx | ||
566 | * SUBS PC,LR,#<imm8> 1111 0011 1101 xxxx 10x0 xxxx xxxx xxxx | ||
567 | * MRS Rd, SPSR 1111 0011 1111 xxxx 10x0 xxxx xxxx xxxx | ||
568 | * SMC 1111 0111 1111 xxxx 1000 xxxx xxxx xxxx | ||
569 | * UNDEFINED 1111 0111 1111 xxxx 1010 xxxx xxxx xxxx | ||
570 | * ??? 1111 0111 1xxx xxxx 1010 xxxx xxxx xxxx | ||
571 | */ | ||
572 | DECODE_REJECT (0xfb80d000, 0xf3808000), | ||
573 | |||
574 | /* Bcc 1111 0xxx xxxx xxxx 10x0 xxxx xxxx xxxx */ | ||
575 | DECODE_CUSTOM (0xf800d000, 0xf0008000, t32_decode_cond_branch), | ||
576 | |||
577 | /* BLX 1111 0xxx xxxx xxxx 11x0 xxxx xxxx xxx0 */ | ||
578 | DECODE_OR (0xf800d001, 0xf000c000), | ||
579 | /* B 1111 0xxx xxxx xxxx 10x1 xxxx xxxx xxxx */ | ||
580 | /* BL 1111 0xxx xxxx xxxx 11x1 xxxx xxxx xxxx */ | ||
581 | DECODE_SIMULATE (0xf8009000, 0xf0009000, t32_simulate_branch), | ||
582 | |||
583 | DECODE_END | ||
584 | }; | ||
585 | |||
586 | static const union decode_item t32_table_1111_100x_x0x1__1111[] = { | ||
587 | /* Memory hints */ | ||
588 | |||
589 | /* PLD (literal) 1111 1000 x001 1111 1111 xxxx xxxx xxxx */ | ||
590 | /* PLI (literal) 1111 1001 x001 1111 1111 xxxx xxxx xxxx */ | ||
591 | DECODE_SIMULATE (0xfe7ff000, 0xf81ff000, kprobe_simulate_nop), | ||
592 | |||
593 | /* PLD{W} (immediate) 1111 1000 10x1 xxxx 1111 xxxx xxxx xxxx */ | ||
594 | DECODE_OR (0xffd0f000, 0xf890f000), | ||
595 | /* PLD{W} (immediate) 1111 1000 00x1 xxxx 1111 1100 xxxx xxxx */ | ||
596 | DECODE_OR (0xffd0ff00, 0xf810fc00), | ||
597 | /* PLI (immediate) 1111 1001 1001 xxxx 1111 xxxx xxxx xxxx */ | ||
598 | DECODE_OR (0xfff0f000, 0xf990f000), | ||
599 | /* PLI (immediate) 1111 1001 0001 xxxx 1111 1100 xxxx xxxx */ | ||
600 | DECODE_SIMULATEX(0xfff0ff00, 0xf910fc00, kprobe_simulate_nop, | ||
601 | REGS(NOPCX, 0, 0, 0, 0)), | ||
602 | |||
603 | /* PLD{W} (register) 1111 1000 00x1 xxxx 1111 0000 00xx xxxx */ | ||
604 | DECODE_OR (0xffd0ffc0, 0xf810f000), | ||
605 | /* PLI (register) 1111 1001 0001 xxxx 1111 0000 00xx xxxx */ | ||
606 | DECODE_SIMULATEX(0xfff0ffc0, 0xf910f000, kprobe_simulate_nop, | ||
607 | REGS(NOPCX, 0, 0, 0, NOSPPC)), | ||
608 | |||
609 | /* Other unallocated instructions... */ | ||
610 | DECODE_END | ||
611 | }; | ||
612 | |||
613 | static const union decode_item t32_table_1111_100x[] = { | ||
614 | /* Store/Load single data item */ | ||
615 | |||
616 | /* ??? 1111 100x x11x xxxx xxxx xxxx xxxx xxxx */ | ||
617 | DECODE_REJECT (0xfe600000, 0xf8600000), | ||
618 | |||
619 | /* ??? 1111 1001 0101 xxxx xxxx xxxx xxxx xxxx */ | ||
620 | DECODE_REJECT (0xfff00000, 0xf9500000), | ||
621 | |||
622 | /* ??? 1111 100x 0xxx xxxx xxxx 10x0 xxxx xxxx */ | ||
623 | DECODE_REJECT (0xfe800d00, 0xf8000800), | ||
624 | |||
625 | /* STRBT 1111 1000 0000 xxxx xxxx 1110 xxxx xxxx */ | ||
626 | /* STRHT 1111 1000 0010 xxxx xxxx 1110 xxxx xxxx */ | ||
627 | /* STRT 1111 1000 0100 xxxx xxxx 1110 xxxx xxxx */ | ||
628 | /* LDRBT 1111 1000 0001 xxxx xxxx 1110 xxxx xxxx */ | ||
629 | /* LDRSBT 1111 1001 0001 xxxx xxxx 1110 xxxx xxxx */ | ||
630 | /* LDRHT 1111 1000 0011 xxxx xxxx 1110 xxxx xxxx */ | ||
631 | /* LDRSHT 1111 1001 0011 xxxx xxxx 1110 xxxx xxxx */ | ||
632 | /* LDRT 1111 1000 0101 xxxx xxxx 1110 xxxx xxxx */ | ||
633 | DECODE_REJECT (0xfe800f00, 0xf8000e00), | ||
634 | |||
635 | /* STR{,B,H} Rn,[PC...] 1111 1000 xxx0 1111 xxxx xxxx xxxx xxxx */ | ||
636 | DECODE_REJECT (0xff1f0000, 0xf80f0000), | ||
637 | |||
638 | /* STR{,B,H} PC,[Rn...] 1111 1000 xxx0 xxxx 1111 xxxx xxxx xxxx */ | ||
639 | DECODE_REJECT (0xff10f000, 0xf800f000), | ||
640 | |||
641 | /* LDR (literal) 1111 1000 x101 1111 xxxx xxxx xxxx xxxx */ | ||
642 | DECODE_SIMULATEX(0xff7f0000, 0xf85f0000, t32_simulate_ldr_literal, | ||
643 | REGS(PC, ANY, 0, 0, 0)), | ||
644 | |||
645 | /* STR (immediate) 1111 1000 0100 xxxx xxxx 1xxx xxxx xxxx */ | ||
646 | /* LDR (immediate) 1111 1000 0101 xxxx xxxx 1xxx xxxx xxxx */ | ||
647 | DECODE_OR (0xffe00800, 0xf8400800), | ||
648 | /* STR (immediate) 1111 1000 1100 xxxx xxxx xxxx xxxx xxxx */ | ||
649 | /* LDR (immediate) 1111 1000 1101 xxxx xxxx xxxx xxxx xxxx */ | ||
650 | DECODE_EMULATEX (0xffe00000, 0xf8c00000, t32_emulate_ldrstr, | ||
651 | REGS(NOPCX, ANY, 0, 0, 0)), | ||
652 | |||
653 | /* STR (register) 1111 1000 0100 xxxx xxxx 0000 00xx xxxx */ | ||
654 | /* LDR (register) 1111 1000 0101 xxxx xxxx 0000 00xx xxxx */ | ||
655 | DECODE_EMULATEX (0xffe00fc0, 0xf8400000, t32_emulate_ldrstr, | ||
656 | REGS(NOPCX, ANY, 0, 0, NOSPPC)), | ||
657 | |||
658 | /* LDRB (literal) 1111 1000 x001 1111 xxxx xxxx xxxx xxxx */ | ||
659 | /* LDRSB (literal) 1111 1001 x001 1111 xxxx xxxx xxxx xxxx */ | ||
660 | /* LDRH (literal) 1111 1000 x011 1111 xxxx xxxx xxxx xxxx */ | ||
661 | /* LDRSH (literal) 1111 1001 x011 1111 xxxx xxxx xxxx xxxx */ | ||
662 | DECODE_EMULATEX (0xfe5f0000, 0xf81f0000, t32_simulate_ldr_literal, | ||
663 | REGS(PC, NOSPPCX, 0, 0, 0)), | ||
664 | |||
665 | /* STRB (immediate) 1111 1000 0000 xxxx xxxx 1xxx xxxx xxxx */ | ||
666 | /* STRH (immediate) 1111 1000 0010 xxxx xxxx 1xxx xxxx xxxx */ | ||
667 | /* LDRB (immediate) 1111 1000 0001 xxxx xxxx 1xxx xxxx xxxx */ | ||
668 | /* LDRSB (immediate) 1111 1001 0001 xxxx xxxx 1xxx xxxx xxxx */ | ||
669 | /* LDRH (immediate) 1111 1000 0011 xxxx xxxx 1xxx xxxx xxxx */ | ||
670 | /* LDRSH (immediate) 1111 1001 0011 xxxx xxxx 1xxx xxxx xxxx */ | ||
671 | DECODE_OR (0xfec00800, 0xf8000800), | ||
672 | /* STRB (immediate) 1111 1000 1000 xxxx xxxx xxxx xxxx xxxx */ | ||
673 | /* STRH (immediate) 1111 1000 1010 xxxx xxxx xxxx xxxx xxxx */ | ||
674 | /* LDRB (immediate) 1111 1000 1001 xxxx xxxx xxxx xxxx xxxx */ | ||
675 | /* LDRSB (immediate) 1111 1001 1001 xxxx xxxx xxxx xxxx xxxx */ | ||
676 | /* LDRH (immediate) 1111 1000 1011 xxxx xxxx xxxx xxxx xxxx */ | ||
677 | /* LDRSH (immediate) 1111 1001 1011 xxxx xxxx xxxx xxxx xxxx */ | ||
678 | DECODE_EMULATEX (0xfec00000, 0xf8800000, t32_emulate_ldrstr, | ||
679 | REGS(NOPCX, NOSPPCX, 0, 0, 0)), | ||
680 | |||
681 | /* STRB (register) 1111 1000 0000 xxxx xxxx 0000 00xx xxxx */ | ||
682 | /* STRH (register) 1111 1000 0010 xxxx xxxx 0000 00xx xxxx */ | ||
683 | /* LDRB (register) 1111 1000 0001 xxxx xxxx 0000 00xx xxxx */ | ||
684 | /* LDRSB (register) 1111 1001 0001 xxxx xxxx 0000 00xx xxxx */ | ||
685 | /* LDRH (register) 1111 1000 0011 xxxx xxxx 0000 00xx xxxx */ | ||
686 | /* LDRSH (register) 1111 1001 0011 xxxx xxxx 0000 00xx xxxx */ | ||
687 | DECODE_EMULATEX (0xfe800fc0, 0xf8000000, t32_emulate_ldrstr, | ||
688 | REGS(NOPCX, NOSPPCX, 0, 0, NOSPPC)), | ||
689 | |||
690 | /* Other unallocated instructions... */ | ||
691 | DECODE_END | ||
692 | }; | ||
693 | |||
694 | static const union decode_item t32_table_1111_1010___1111[] = { | ||
695 | /* Data-processing (register) */ | ||
696 | |||
697 | /* ??? 1111 1010 011x xxxx 1111 xxxx 1xxx xxxx */ | ||
698 | DECODE_REJECT (0xffe0f080, 0xfa60f080), | ||
699 | |||
700 | /* SXTH 1111 1010 0000 1111 1111 xxxx 1xxx xxxx */ | ||
701 | /* UXTH 1111 1010 0001 1111 1111 xxxx 1xxx xxxx */ | ||
702 | /* SXTB16 1111 1010 0010 1111 1111 xxxx 1xxx xxxx */ | ||
703 | /* UXTB16 1111 1010 0011 1111 1111 xxxx 1xxx xxxx */ | ||
704 | /* SXTB 1111 1010 0100 1111 1111 xxxx 1xxx xxxx */ | ||
705 | /* UXTB 1111 1010 0101 1111 1111 xxxx 1xxx xxxx */ | ||
706 | DECODE_EMULATEX (0xff8ff080, 0xfa0ff080, t32_emulate_rd8rn16rm0_rwflags, | ||
707 | REGS(0, 0, NOSPPC, 0, NOSPPC)), | ||
708 | |||
709 | |||
710 | /* ??? 1111 1010 1xxx xxxx 1111 xxxx 0x11 xxxx */ | ||
711 | DECODE_REJECT (0xff80f0b0, 0xfa80f030), | ||
712 | /* ??? 1111 1010 1x11 xxxx 1111 xxxx 0xxx xxxx */ | ||
713 | DECODE_REJECT (0xffb0f080, 0xfab0f000), | ||
714 | |||
715 | /* SADD16 1111 1010 1001 xxxx 1111 xxxx 0000 xxxx */ | ||
716 | /* SASX 1111 1010 1010 xxxx 1111 xxxx 0000 xxxx */ | ||
717 | /* SSAX 1111 1010 1110 xxxx 1111 xxxx 0000 xxxx */ | ||
718 | /* SSUB16 1111 1010 1101 xxxx 1111 xxxx 0000 xxxx */ | ||
719 | /* SADD8 1111 1010 1000 xxxx 1111 xxxx 0000 xxxx */ | ||
720 | /* SSUB8 1111 1010 1100 xxxx 1111 xxxx 0000 xxxx */ | ||
721 | |||
722 | /* QADD16 1111 1010 1001 xxxx 1111 xxxx 0001 xxxx */ | ||
723 | /* QASX 1111 1010 1010 xxxx 1111 xxxx 0001 xxxx */ | ||
724 | /* QSAX 1111 1010 1110 xxxx 1111 xxxx 0001 xxxx */ | ||
725 | /* QSUB16 1111 1010 1101 xxxx 1111 xxxx 0001 xxxx */ | ||
726 | /* QADD8 1111 1010 1000 xxxx 1111 xxxx 0001 xxxx */ | ||
727 | /* QSUB8 1111 1010 1100 xxxx 1111 xxxx 0001 xxxx */ | ||
728 | |||
729 | /* SHADD16 1111 1010 1001 xxxx 1111 xxxx 0010 xxxx */ | ||
730 | /* SHASX 1111 1010 1010 xxxx 1111 xxxx 0010 xxxx */ | ||
731 | /* SHSAX 1111 1010 1110 xxxx 1111 xxxx 0010 xxxx */ | ||
732 | /* SHSUB16 1111 1010 1101 xxxx 1111 xxxx 0010 xxxx */ | ||
733 | /* SHADD8 1111 1010 1000 xxxx 1111 xxxx 0010 xxxx */ | ||
734 | /* SHSUB8 1111 1010 1100 xxxx 1111 xxxx 0010 xxxx */ | ||
735 | |||
736 | /* UADD16 1111 1010 1001 xxxx 1111 xxxx 0100 xxxx */ | ||
737 | /* UASX 1111 1010 1010 xxxx 1111 xxxx 0100 xxxx */ | ||
738 | /* USAX 1111 1010 1110 xxxx 1111 xxxx 0100 xxxx */ | ||
739 | /* USUB16 1111 1010 1101 xxxx 1111 xxxx 0100 xxxx */ | ||
740 | /* UADD8 1111 1010 1000 xxxx 1111 xxxx 0100 xxxx */ | ||
741 | /* USUB8 1111 1010 1100 xxxx 1111 xxxx 0100 xxxx */ | ||
742 | |||
743 | /* UQADD16 1111 1010 1001 xxxx 1111 xxxx 0101 xxxx */ | ||
744 | /* UQASX 1111 1010 1010 xxxx 1111 xxxx 0101 xxxx */ | ||
745 | /* UQSAX 1111 1010 1110 xxxx 1111 xxxx 0101 xxxx */ | ||
746 | /* UQSUB16 1111 1010 1101 xxxx 1111 xxxx 0101 xxxx */ | ||
747 | /* UQADD8 1111 1010 1000 xxxx 1111 xxxx 0101 xxxx */ | ||
748 | /* UQSUB8 1111 1010 1100 xxxx 1111 xxxx 0101 xxxx */ | ||
749 | |||
750 | /* UHADD16 1111 1010 1001 xxxx 1111 xxxx 0110 xxxx */ | ||
751 | /* UHASX 1111 1010 1010 xxxx 1111 xxxx 0110 xxxx */ | ||
752 | /* UHSAX 1111 1010 1110 xxxx 1111 xxxx 0110 xxxx */ | ||
753 | /* UHSUB16 1111 1010 1101 xxxx 1111 xxxx 0110 xxxx */ | ||
754 | /* UHADD8 1111 1010 1000 xxxx 1111 xxxx 0110 xxxx */ | ||
755 | /* UHSUB8 1111 1010 1100 xxxx 1111 xxxx 0110 xxxx */ | ||
756 | DECODE_OR (0xff80f080, 0xfa80f000), | ||
757 | |||
758 | /* SXTAH 1111 1010 0000 xxxx 1111 xxxx 1xxx xxxx */ | ||
759 | /* UXTAH 1111 1010 0001 xxxx 1111 xxxx 1xxx xxxx */ | ||
760 | /* SXTAB16 1111 1010 0010 xxxx 1111 xxxx 1xxx xxxx */ | ||
761 | /* UXTAB16 1111 1010 0011 xxxx 1111 xxxx 1xxx xxxx */ | ||
762 | /* SXTAB 1111 1010 0100 xxxx 1111 xxxx 1xxx xxxx */ | ||
763 | /* UXTAB 1111 1010 0101 xxxx 1111 xxxx 1xxx xxxx */ | ||
764 | DECODE_OR (0xff80f080, 0xfa00f080), | ||
765 | |||
766 | /* QADD 1111 1010 1000 xxxx 1111 xxxx 1000 xxxx */ | ||
767 | /* QDADD 1111 1010 1000 xxxx 1111 xxxx 1001 xxxx */ | ||
768 | /* QSUB 1111 1010 1000 xxxx 1111 xxxx 1010 xxxx */ | ||
769 | /* QDSUB 1111 1010 1000 xxxx 1111 xxxx 1011 xxxx */ | ||
770 | DECODE_OR (0xfff0f0c0, 0xfa80f080), | ||
771 | |||
772 | /* SEL 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ | ||
773 | DECODE_OR (0xfff0f0f0, 0xfaa0f080), | ||
774 | |||
775 | /* LSL 1111 1010 000x xxxx 1111 xxxx 0000 xxxx */ | ||
776 | /* LSR 1111 1010 001x xxxx 1111 xxxx 0000 xxxx */ | ||
777 | /* ASR 1111 1010 010x xxxx 1111 xxxx 0000 xxxx */ | ||
778 | /* ROR 1111 1010 011x xxxx 1111 xxxx 0000 xxxx */ | ||
779 | DECODE_EMULATEX (0xff80f0f0, 0xfa00f000, t32_emulate_rd8rn16rm0_rwflags, | ||
780 | REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), | ||
781 | |||
782 | /* CLZ 1111 1010 1010 xxxx 1111 xxxx 1000 xxxx */ | ||
783 | DECODE_OR (0xfff0f0f0, 0xfab0f080), | ||
784 | |||
785 | /* REV 1111 1010 1001 xxxx 1111 xxxx 1000 xxxx */ | ||
786 | /* REV16 1111 1010 1001 xxxx 1111 xxxx 1001 xxxx */ | ||
787 | /* RBIT 1111 1010 1001 xxxx 1111 xxxx 1010 xxxx */ | ||
788 | /* REVSH 1111 1010 1001 xxxx 1111 xxxx 1011 xxxx */ | ||
789 | DECODE_EMULATEX (0xfff0f0c0, 0xfa90f080, t32_emulate_rd8rn16_noflags, | ||
790 | REGS(NOSPPC, 0, NOSPPC, 0, SAMEAS16)), | ||
791 | |||
792 | /* Other unallocated instructions... */ | ||
793 | DECODE_END | ||
794 | }; | ||
795 | |||
796 | static const union decode_item t32_table_1111_1011_0[] = { | ||
797 | /* Multiply, multiply accumulate, and absolute difference */ | ||
798 | |||
799 | /* ??? 1111 1011 0000 xxxx 1111 xxxx 0001 xxxx */ | ||
800 | DECODE_REJECT (0xfff0f0f0, 0xfb00f010), | ||
801 | /* ??? 1111 1011 0111 xxxx 1111 xxxx 0001 xxxx */ | ||
802 | DECODE_REJECT (0xfff0f0f0, 0xfb70f010), | ||
803 | |||
804 | /* SMULxy 1111 1011 0001 xxxx 1111 xxxx 00xx xxxx */ | ||
805 | DECODE_OR (0xfff0f0c0, 0xfb10f000), | ||
806 | /* MUL 1111 1011 0000 xxxx 1111 xxxx 0000 xxxx */ | ||
807 | /* SMUAD{X} 1111 1011 0010 xxxx 1111 xxxx 000x xxxx */ | ||
808 | /* SMULWy 1111 1011 0011 xxxx 1111 xxxx 000x xxxx */ | ||
809 | /* SMUSD{X} 1111 1011 0100 xxxx 1111 xxxx 000x xxxx */ | ||
810 | /* SMMUL{R} 1111 1011 0101 xxxx 1111 xxxx 000x xxxx */ | ||
811 | /* USAD8 1111 1011 0111 xxxx 1111 xxxx 0000 xxxx */ | ||
812 | DECODE_EMULATEX (0xff80f0e0, 0xfb00f000, t32_emulate_rd8rn16rm0_rwflags, | ||
813 | REGS(NOSPPC, 0, NOSPPC, 0, NOSPPC)), | ||
814 | |||
815 | /* ??? 1111 1011 0111 xxxx xxxx xxxx 0001 xxxx */ | ||
816 | DECODE_REJECT (0xfff000f0, 0xfb700010), | ||
817 | |||
818 | /* SMLAxy 1111 1011 0001 xxxx xxxx xxxx 00xx xxxx */ | ||
819 | DECODE_OR (0xfff000c0, 0xfb100000), | ||
820 | /* MLA 1111 1011 0000 xxxx xxxx xxxx 0000 xxxx */ | ||
821 | /* MLS 1111 1011 0000 xxxx xxxx xxxx 0001 xxxx */ | ||
822 | /* SMLAD{X} 1111 1011 0010 xxxx xxxx xxxx 000x xxxx */ | ||
823 | /* SMLAWy 1111 1011 0011 xxxx xxxx xxxx 000x xxxx */ | ||
824 | /* SMLSD{X} 1111 1011 0100 xxxx xxxx xxxx 000x xxxx */ | ||
825 | /* SMMLA{R} 1111 1011 0101 xxxx xxxx xxxx 000x xxxx */ | ||
826 | /* SMMLS{R} 1111 1011 0110 xxxx xxxx xxxx 000x xxxx */ | ||
827 | /* USADA8 1111 1011 0111 xxxx xxxx xxxx 0000 xxxx */ | ||
828 | DECODE_EMULATEX (0xff8000c0, 0xfb000000, t32_emulate_rd8rn16rm0ra12_noflags, | ||
829 | REGS(NOSPPC, NOSPPCX, NOSPPC, 0, NOSPPC)), | ||
830 | |||
831 | /* Other unallocated instructions... */ | ||
832 | DECODE_END | ||
833 | }; | ||
834 | |||
835 | static const union decode_item t32_table_1111_1011_1[] = { | ||
836 | /* Long multiply, long multiply accumulate, and divide */ | ||
837 | |||
838 | /* UMAAL 1111 1011 1110 xxxx xxxx xxxx 0110 xxxx */ | ||
839 | DECODE_OR (0xfff000f0, 0xfbe00060), | ||
840 | /* SMLALxy 1111 1011 1100 xxxx xxxx xxxx 10xx xxxx */ | ||
841 | DECODE_OR (0xfff000c0, 0xfbc00080), | ||
842 | /* SMLALD{X} 1111 1011 1100 xxxx xxxx xxxx 110x xxxx */ | ||
843 | /* SMLSLD{X} 1111 1011 1101 xxxx xxxx xxxx 110x xxxx */ | ||
844 | DECODE_OR (0xffe000e0, 0xfbc000c0), | ||
845 | /* SMULL 1111 1011 1000 xxxx xxxx xxxx 0000 xxxx */ | ||
846 | /* UMULL 1111 1011 1010 xxxx xxxx xxxx 0000 xxxx */ | ||
847 | /* SMLAL 1111 1011 1100 xxxx xxxx xxxx 0000 xxxx */ | ||
848 | /* UMLAL 1111 1011 1110 xxxx xxxx xxxx 0000 xxxx */ | ||
849 | DECODE_EMULATEX (0xff9000f0, 0xfb800000, t32_emulate_rdlo12rdhi8rn16rm0_noflags, | ||
850 | REGS(NOSPPC, NOSPPC, NOSPPC, 0, NOSPPC)), | ||
851 | |||
852 | /* SDIV 1111 1011 1001 xxxx xxxx xxxx 1111 xxxx */ | ||
853 | /* UDIV 1111 1011 1011 xxxx xxxx xxxx 1111 xxxx */ | ||
854 | /* Other unallocated instructions... */ | ||
855 | DECODE_END | ||
856 | }; | ||
857 | |||
858 | const union decode_item kprobe_decode_thumb32_table[] = { | ||
859 | |||
860 | /* | ||
861 | * Load/store multiple instructions | ||
862 | * 1110 100x x0xx xxxx xxxx xxxx xxxx xxxx | ||
863 | */ | ||
864 | DECODE_TABLE (0xfe400000, 0xe8000000, t32_table_1110_100x_x0xx), | ||
865 | |||
866 | /* | ||
867 | * Load/store dual, load/store exclusive, table branch | ||
868 | * 1110 100x x1xx xxxx xxxx xxxx xxxx xxxx | ||
869 | */ | ||
870 | DECODE_TABLE (0xfe400000, 0xe8400000, t32_table_1110_100x_x1xx), | ||
871 | |||
872 | /* | ||
873 | * Data-processing (shifted register) | ||
874 | * 1110 101x xxxx xxxx xxxx xxxx xxxx xxxx | ||
875 | */ | ||
876 | DECODE_TABLE (0xfe000000, 0xea000000, t32_table_1110_101x), | ||
877 | |||
878 | /* | ||
879 | * Coprocessor instructions | ||
880 | * 1110 11xx xxxx xxxx xxxx xxxx xxxx xxxx | ||
881 | */ | ||
882 | DECODE_REJECT (0xfc000000, 0xec000000), | ||
883 | |||
884 | /* | ||
885 | * Data-processing (modified immediate) | ||
886 | * 1111 0x0x xxxx xxxx 0xxx xxxx xxxx xxxx | ||
887 | */ | ||
888 | DECODE_TABLE (0xfa008000, 0xf0000000, t32_table_1111_0x0x___0), | ||
889 | |||
890 | /* | ||
891 | * Data-processing (plain binary immediate) | ||
892 | * 1111 0x1x xxxx xxxx 0xxx xxxx xxxx xxxx | ||
893 | */ | ||
894 | DECODE_TABLE (0xfa008000, 0xf2000000, t32_table_1111_0x1x___0), | ||
895 | |||
896 | /* | ||
897 | * Branches and miscellaneous control | ||
898 | * 1111 0xxx xxxx xxxx 1xxx xxxx xxxx xxxx | ||
899 | */ | ||
900 | DECODE_TABLE (0xf8008000, 0xf0008000, t32_table_1111_0xxx___1), | ||
901 | |||
902 | /* | ||
903 | * Advanced SIMD element or structure load/store instructions | ||
904 | * 1111 1001 xxx0 xxxx xxxx xxxx xxxx xxxx | ||
905 | */ | ||
906 | DECODE_REJECT (0xff100000, 0xf9000000), | ||
907 | |||
908 | /* | ||
909 | * Memory hints | ||
910 | * 1111 100x x0x1 xxxx 1111 xxxx xxxx xxxx | ||
911 | */ | ||
912 | DECODE_TABLE (0xfe50f000, 0xf810f000, t32_table_1111_100x_x0x1__1111), | ||
913 | |||
914 | /* | ||
915 | * Store single data item | ||
916 | * 1111 1000 xxx0 xxxx xxxx xxxx xxxx xxxx | ||
917 | * Load single data items | ||
918 | * 1111 100x xxx1 xxxx xxxx xxxx xxxx xxxx | ||
919 | */ | ||
920 | DECODE_TABLE (0xfe000000, 0xf8000000, t32_table_1111_100x), | ||
921 | |||
922 | /* | ||
923 | * Data-processing (register) | ||
924 | * 1111 1010 xxxx xxxx 1111 xxxx xxxx xxxx | ||
925 | */ | ||
926 | DECODE_TABLE (0xff00f000, 0xfa00f000, t32_table_1111_1010___1111), | ||
927 | |||
928 | /* | ||
929 | * Multiply, multiply accumulate, and absolute difference | ||
930 | * 1111 1011 0xxx xxxx xxxx xxxx xxxx xxxx | ||
931 | */ | ||
932 | DECODE_TABLE (0xff800000, 0xfb000000, t32_table_1111_1011_0), | ||
933 | |||
934 | /* | ||
935 | * Long multiply, long multiply accumulate, and divide | ||
936 | * 1111 1011 1xxx xxxx xxxx xxxx xxxx xxxx | ||
937 | */ | ||
938 | DECODE_TABLE (0xff800000, 0xfb800000, t32_table_1111_1011_1), | ||
939 | |||
940 | /* | ||
941 | * Coprocessor instructions | ||
942 | * 1111 11xx xxxx xxxx xxxx xxxx xxxx xxxx | ||
943 | */ | ||
944 | DECODE_END | ||
945 | }; | ||
946 | |||
947 | static void __kprobes | ||
948 | t16_simulate_bxblx(struct kprobe *p, struct pt_regs *regs) | ||
949 | { | ||
950 | kprobe_opcode_t insn = p->opcode; | ||
951 | unsigned long pc = thumb_probe_pc(p); | ||
952 | int rm = (insn >> 3) & 0xf; | ||
953 | unsigned long rmv = (rm == 15) ? pc : regs->uregs[rm]; | ||
954 | |||
955 | if (insn & (1 << 7)) /* BLX ? */ | ||
956 | regs->ARM_lr = (unsigned long)p->addr + 2; | ||
957 | |||
958 | bx_write_pc(rmv, regs); | ||
959 | } | ||
960 | |||
961 | static void __kprobes | ||
962 | t16_simulate_ldr_literal(struct kprobe *p, struct pt_regs *regs) | ||
963 | { | ||
964 | kprobe_opcode_t insn = p->opcode; | ||
965 | unsigned long* base = (unsigned long *)(thumb_probe_pc(p) & ~3); | ||
966 | long index = insn & 0xff; | ||
967 | int rt = (insn >> 8) & 0x7; | ||
968 | regs->uregs[rt] = base[index]; | ||
969 | } | ||
970 | |||
971 | static void __kprobes | ||
972 | t16_simulate_ldrstr_sp_relative(struct kprobe *p, struct pt_regs *regs) | ||
973 | { | ||
974 | kprobe_opcode_t insn = p->opcode; | ||
975 | unsigned long* base = (unsigned long *)regs->ARM_sp; | ||
976 | long index = insn & 0xff; | ||
977 | int rt = (insn >> 8) & 0x7; | ||
978 | if (insn & 0x800) /* LDR */ | ||
979 | regs->uregs[rt] = base[index]; | ||
980 | else /* STR */ | ||
981 | base[index] = regs->uregs[rt]; | ||
982 | } | ||
983 | |||
984 | static void __kprobes | ||
985 | t16_simulate_reladr(struct kprobe *p, struct pt_regs *regs) | ||
986 | { | ||
987 | kprobe_opcode_t insn = p->opcode; | ||
988 | unsigned long base = (insn & 0x800) ? regs->ARM_sp | ||
989 | : (thumb_probe_pc(p) & ~3); | ||
990 | long offset = insn & 0xff; | ||
991 | int rt = (insn >> 8) & 0x7; | ||
992 | regs->uregs[rt] = base + offset * 4; | ||
993 | } | ||
994 | |||
995 | static void __kprobes | ||
996 | t16_simulate_add_sp_imm(struct kprobe *p, struct pt_regs *regs) | ||
997 | { | ||
998 | kprobe_opcode_t insn = p->opcode; | ||
999 | long imm = insn & 0x7f; | ||
1000 | if (insn & 0x80) /* SUB */ | ||
1001 | regs->ARM_sp -= imm * 4; | ||
1002 | else /* ADD */ | ||
1003 | regs->ARM_sp += imm * 4; | ||
1004 | } | ||
1005 | |||
1006 | static void __kprobes | ||
1007 | t16_simulate_cbz(struct kprobe *p, struct pt_regs *regs) | ||
1008 | { | ||
1009 | kprobe_opcode_t insn = p->opcode; | ||
1010 | int rn = insn & 0x7; | ||
1011 | kprobe_opcode_t nonzero = regs->uregs[rn] ? insn : ~insn; | ||
1012 | if (nonzero & 0x800) { | ||
1013 | long i = insn & 0x200; | ||
1014 | long imm5 = insn & 0xf8; | ||
1015 | unsigned long pc = thumb_probe_pc(p); | ||
1016 | regs->ARM_pc = pc + (i >> 3) + (imm5 >> 2); | ||
1017 | } | ||
1018 | } | ||
1019 | |||
1020 | static void __kprobes | ||
1021 | t16_simulate_it(struct kprobe *p, struct pt_regs *regs) | ||
1022 | { | ||
1023 | /* | ||
1024 | * The 8 IT state bits are split into two parts in CPSR: | ||
1025 | * ITSTATE<1:0> are in CPSR<26:25> | ||
1026 | * ITSTATE<7:2> are in CPSR<15:10> | ||
1027 | * The new IT state is in the lower byte of insn. | ||
1028 | */ | ||
1029 | kprobe_opcode_t insn = p->opcode; | ||
1030 | unsigned long cpsr = regs->ARM_cpsr; | ||
1031 | cpsr &= ~PSR_IT_MASK; | ||
1032 | cpsr |= (insn & 0xfc) << 8; | ||
1033 | cpsr |= (insn & 0x03) << 25; | ||
1034 | regs->ARM_cpsr = cpsr; | ||
1035 | } | ||
1036 | |||
1037 | static void __kprobes | ||
1038 | t16_singlestep_it(struct kprobe *p, struct pt_regs *regs) | ||
1039 | { | ||
1040 | regs->ARM_pc += 2; | ||
1041 | t16_simulate_it(p, regs); | ||
1042 | } | ||
1043 | |||
1044 | static enum kprobe_insn __kprobes | ||
1045 | t16_decode_it(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1046 | { | ||
1047 | asi->insn_singlestep = t16_singlestep_it; | ||
1048 | return INSN_GOOD_NO_SLOT; | ||
1049 | } | ||
1050 | |||
1051 | static void __kprobes | ||
1052 | t16_simulate_cond_branch(struct kprobe *p, struct pt_regs *regs) | ||
1053 | { | ||
1054 | kprobe_opcode_t insn = p->opcode; | ||
1055 | unsigned long pc = thumb_probe_pc(p); | ||
1056 | long offset = insn & 0x7f; | ||
1057 | offset -= insn & 0x80; /* Apply sign bit */ | ||
1058 | regs->ARM_pc = pc + (offset * 2); | ||
1059 | } | ||
1060 | |||
1061 | static enum kprobe_insn __kprobes | ||
1062 | t16_decode_cond_branch(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1063 | { | ||
1064 | int cc = (insn >> 8) & 0xf; | ||
1065 | asi->insn_check_cc = kprobe_condition_checks[cc]; | ||
1066 | asi->insn_handler = t16_simulate_cond_branch; | ||
1067 | return INSN_GOOD_NO_SLOT; | ||
1068 | } | ||
1069 | |||
1070 | static void __kprobes | ||
1071 | t16_simulate_branch(struct kprobe *p, struct pt_regs *regs) | ||
1072 | { | ||
1073 | kprobe_opcode_t insn = p->opcode; | ||
1074 | unsigned long pc = thumb_probe_pc(p); | ||
1075 | long offset = insn & 0x3ff; | ||
1076 | offset -= insn & 0x400; /* Apply sign bit */ | ||
1077 | regs->ARM_pc = pc + (offset * 2); | ||
1078 | } | ||
1079 | |||
1080 | static unsigned long __kprobes | ||
1081 | t16_emulate_loregs(struct kprobe *p, struct pt_regs *regs) | ||
1082 | { | ||
1083 | unsigned long oldcpsr = regs->ARM_cpsr; | ||
1084 | unsigned long newcpsr; | ||
1085 | |||
1086 | __asm__ __volatile__ ( | ||
1087 | "msr cpsr_fs, %[oldcpsr] \n\t" | ||
1088 | "ldmia %[regs], {r0-r7} \n\t" | ||
1089 | "blx %[fn] \n\t" | ||
1090 | "stmia %[regs], {r0-r7} \n\t" | ||
1091 | "mrs %[newcpsr], cpsr \n\t" | ||
1092 | : [newcpsr] "=r" (newcpsr) | ||
1093 | : [oldcpsr] "r" (oldcpsr), [regs] "r" (regs), | ||
1094 | [fn] "r" (p->ainsn.insn_fn) | ||
1095 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", | ||
1096 | "lr", "memory", "cc" | ||
1097 | ); | ||
1098 | |||
1099 | return (oldcpsr & ~APSR_MASK) | (newcpsr & APSR_MASK); | ||
1100 | } | ||
1101 | |||
1102 | static void __kprobes | ||
1103 | t16_emulate_loregs_rwflags(struct kprobe *p, struct pt_regs *regs) | ||
1104 | { | ||
1105 | regs->ARM_cpsr = t16_emulate_loregs(p, regs); | ||
1106 | } | ||
1107 | |||
1108 | static void __kprobes | ||
1109 | t16_emulate_loregs_noitrwflags(struct kprobe *p, struct pt_regs *regs) | ||
1110 | { | ||
1111 | unsigned long cpsr = t16_emulate_loregs(p, regs); | ||
1112 | if (!in_it_block(cpsr)) | ||
1113 | regs->ARM_cpsr = cpsr; | ||
1114 | } | ||
1115 | |||
1116 | static void __kprobes | ||
1117 | t16_emulate_hiregs(struct kprobe *p, struct pt_regs *regs) | ||
1118 | { | ||
1119 | kprobe_opcode_t insn = p->opcode; | ||
1120 | unsigned long pc = thumb_probe_pc(p); | ||
1121 | int rdn = (insn & 0x7) | ((insn & 0x80) >> 4); | ||
1122 | int rm = (insn >> 3) & 0xf; | ||
1123 | |||
1124 | register unsigned long rdnv asm("r1"); | ||
1125 | register unsigned long rmv asm("r0"); | ||
1126 | unsigned long cpsr = regs->ARM_cpsr; | ||
1127 | |||
1128 | rdnv = (rdn == 15) ? pc : regs->uregs[rdn]; | ||
1129 | rmv = (rm == 15) ? pc : regs->uregs[rm]; | ||
1130 | |||
1131 | __asm__ __volatile__ ( | ||
1132 | "msr cpsr_fs, %[cpsr] \n\t" | ||
1133 | "blx %[fn] \n\t" | ||
1134 | "mrs %[cpsr], cpsr \n\t" | ||
1135 | : "=r" (rdnv), [cpsr] "=r" (cpsr) | ||
1136 | : "0" (rdnv), "r" (rmv), "1" (cpsr), [fn] "r" (p->ainsn.insn_fn) | ||
1137 | : "lr", "memory", "cc" | ||
1138 | ); | ||
1139 | |||
1140 | if (rdn == 15) | ||
1141 | rdnv &= ~1; | ||
1142 | |||
1143 | regs->uregs[rdn] = rdnv; | ||
1144 | regs->ARM_cpsr = (regs->ARM_cpsr & ~APSR_MASK) | (cpsr & APSR_MASK); | ||
1145 | } | ||
1146 | |||
1147 | static enum kprobe_insn __kprobes | ||
1148 | t16_decode_hiregs(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1149 | { | ||
1150 | insn &= ~0x00ff; | ||
1151 | insn |= 0x001; /* Set Rdn = R1 and Rm = R0 */ | ||
1152 | ((u16 *)asi->insn)[0] = insn; | ||
1153 | asi->insn_handler = t16_emulate_hiregs; | ||
1154 | return INSN_GOOD; | ||
1155 | } | ||
1156 | |||
1157 | static void __kprobes | ||
1158 | t16_emulate_push(struct kprobe *p, struct pt_regs *regs) | ||
1159 | { | ||
1160 | __asm__ __volatile__ ( | ||
1161 | "ldr r9, [%[regs], #13*4] \n\t" | ||
1162 | "ldr r8, [%[regs], #14*4] \n\t" | ||
1163 | "ldmia %[regs], {r0-r7} \n\t" | ||
1164 | "blx %[fn] \n\t" | ||
1165 | "str r9, [%[regs], #13*4] \n\t" | ||
1166 | : | ||
1167 | : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) | ||
1168 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", | ||
1169 | "lr", "memory", "cc" | ||
1170 | ); | ||
1171 | } | ||
1172 | |||
1173 | static enum kprobe_insn __kprobes | ||
1174 | t16_decode_push(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1175 | { | ||
1176 | /* | ||
1177 | * To simulate a PUSH we use a Thumb-2 "STMDB R9!, {registers}" | ||
1178 | * and call it with R9=SP and LR in the register list represented | ||
1179 | * by R8. | ||
1180 | */ | ||
1181 | ((u16 *)asi->insn)[0] = 0xe929; /* 1st half STMDB R9!,{} */ | ||
1182 | ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ | ||
1183 | asi->insn_handler = t16_emulate_push; | ||
1184 | return INSN_GOOD; | ||
1185 | } | ||
1186 | |||
1187 | static void __kprobes | ||
1188 | t16_emulate_pop_nopc(struct kprobe *p, struct pt_regs *regs) | ||
1189 | { | ||
1190 | __asm__ __volatile__ ( | ||
1191 | "ldr r9, [%[regs], #13*4] \n\t" | ||
1192 | "ldmia %[regs], {r0-r7} \n\t" | ||
1193 | "blx %[fn] \n\t" | ||
1194 | "stmia %[regs], {r0-r7} \n\t" | ||
1195 | "str r9, [%[regs], #13*4] \n\t" | ||
1196 | : | ||
1197 | : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) | ||
1198 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", | ||
1199 | "lr", "memory", "cc" | ||
1200 | ); | ||
1201 | } | ||
1202 | |||
1203 | static void __kprobes | ||
1204 | t16_emulate_pop_pc(struct kprobe *p, struct pt_regs *regs) | ||
1205 | { | ||
1206 | register unsigned long pc asm("r8"); | ||
1207 | |||
1208 | __asm__ __volatile__ ( | ||
1209 | "ldr r9, [%[regs], #13*4] \n\t" | ||
1210 | "ldmia %[regs], {r0-r7} \n\t" | ||
1211 | "blx %[fn] \n\t" | ||
1212 | "stmia %[regs], {r0-r7} \n\t" | ||
1213 | "str r9, [%[regs], #13*4] \n\t" | ||
1214 | : "=r" (pc) | ||
1215 | : [regs] "r" (regs), [fn] "r" (p->ainsn.insn_fn) | ||
1216 | : "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r9", | ||
1217 | "lr", "memory", "cc" | ||
1218 | ); | ||
1219 | |||
1220 | bx_write_pc(pc, regs); | ||
1221 | } | ||
1222 | |||
1223 | static enum kprobe_insn __kprobes | ||
1224 | t16_decode_pop(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1225 | { | ||
1226 | /* | ||
1227 | * To simulate a POP we use a Thumb-2 "LDMDB R9!, {registers}" | ||
1228 | * and call it with R9=SP and PC in the register list represented | ||
1229 | * by R8. | ||
1230 | */ | ||
1231 | ((u16 *)asi->insn)[0] = 0xe8b9; /* 1st half LDMIA R9!,{} */ | ||
1232 | ((u16 *)asi->insn)[1] = insn & 0x1ff; /* 2nd half (register list) */ | ||
1233 | asi->insn_handler = insn & 0x100 ? t16_emulate_pop_pc | ||
1234 | : t16_emulate_pop_nopc; | ||
1235 | return INSN_GOOD; | ||
1236 | } | ||
1237 | |||
1238 | static const union decode_item t16_table_1011[] = { | ||
1239 | /* Miscellaneous 16-bit instructions */ | ||
1240 | |||
1241 | /* ADD (SP plus immediate) 1011 0000 0xxx xxxx */ | ||
1242 | /* SUB (SP minus immediate) 1011 0000 1xxx xxxx */ | ||
1243 | DECODE_SIMULATE (0xff00, 0xb000, t16_simulate_add_sp_imm), | ||
1244 | |||
1245 | /* CBZ 1011 00x1 xxxx xxxx */ | ||
1246 | /* CBNZ 1011 10x1 xxxx xxxx */ | ||
1247 | DECODE_SIMULATE (0xf500, 0xb100, t16_simulate_cbz), | ||
1248 | |||
1249 | /* SXTH 1011 0010 00xx xxxx */ | ||
1250 | /* SXTB 1011 0010 01xx xxxx */ | ||
1251 | /* UXTH 1011 0010 10xx xxxx */ | ||
1252 | /* UXTB 1011 0010 11xx xxxx */ | ||
1253 | /* REV 1011 1010 00xx xxxx */ | ||
1254 | /* REV16 1011 1010 01xx xxxx */ | ||
1255 | /* ??? 1011 1010 10xx xxxx */ | ||
1256 | /* REVSH 1011 1010 11xx xxxx */ | ||
1257 | DECODE_REJECT (0xffc0, 0xba80), | ||
1258 | DECODE_EMULATE (0xf500, 0xb000, t16_emulate_loregs_rwflags), | ||
1259 | |||
1260 | /* PUSH 1011 010x xxxx xxxx */ | ||
1261 | DECODE_CUSTOM (0xfe00, 0xb400, t16_decode_push), | ||
1262 | /* POP 1011 110x xxxx xxxx */ | ||
1263 | DECODE_CUSTOM (0xfe00, 0xbc00, t16_decode_pop), | ||
1264 | |||
1265 | /* | ||
1266 | * If-Then, and hints | ||
1267 | * 1011 1111 xxxx xxxx | ||
1268 | */ | ||
1269 | |||
1270 | /* YIELD 1011 1111 0001 0000 */ | ||
1271 | DECODE_OR (0xffff, 0xbf10), | ||
1272 | /* SEV 1011 1111 0100 0000 */ | ||
1273 | DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), | ||
1274 | /* NOP 1011 1111 0000 0000 */ | ||
1275 | /* WFE 1011 1111 0010 0000 */ | ||
1276 | /* WFI 1011 1111 0011 0000 */ | ||
1277 | DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), | ||
1278 | /* Unassigned hints 1011 1111 xxxx 0000 */ | ||
1279 | DECODE_REJECT (0xff0f, 0xbf00), | ||
1280 | /* IT 1011 1111 xxxx xxxx */ | ||
1281 | DECODE_CUSTOM (0xff00, 0xbf00, t16_decode_it), | ||
1282 | |||
1283 | /* SETEND 1011 0110 010x xxxx */ | ||
1284 | /* CPS 1011 0110 011x xxxx */ | ||
1285 | /* BKPT 1011 1110 xxxx xxxx */ | ||
1286 | /* And unallocated instructions... */ | ||
1287 | DECODE_END | ||
1288 | }; | ||
1289 | |||
1290 | const union decode_item kprobe_decode_thumb16_table[] = { | ||
1291 | |||
1292 | /* | ||
1293 | * Shift (immediate), add, subtract, move, and compare | ||
1294 | * 00xx xxxx xxxx xxxx | ||
1295 | */ | ||
1296 | |||
1297 | /* CMP (immediate) 0010 1xxx xxxx xxxx */ | ||
1298 | DECODE_EMULATE (0xf800, 0x2800, t16_emulate_loregs_rwflags), | ||
1299 | |||
1300 | /* ADD (register) 0001 100x xxxx xxxx */ | ||
1301 | /* SUB (register) 0001 101x xxxx xxxx */ | ||
1302 | /* LSL (immediate) 0000 0xxx xxxx xxxx */ | ||
1303 | /* LSR (immediate) 0000 1xxx xxxx xxxx */ | ||
1304 | /* ASR (immediate) 0001 0xxx xxxx xxxx */ | ||
1305 | /* ADD (immediate, Thumb) 0001 110x xxxx xxxx */ | ||
1306 | /* SUB (immediate, Thumb) 0001 111x xxxx xxxx */ | ||
1307 | /* MOV (immediate) 0010 0xxx xxxx xxxx */ | ||
1308 | /* ADD (immediate, Thumb) 0011 0xxx xxxx xxxx */ | ||
1309 | /* SUB (immediate, Thumb) 0011 1xxx xxxx xxxx */ | ||
1310 | DECODE_EMULATE (0xc000, 0x0000, t16_emulate_loregs_noitrwflags), | ||
1311 | |||
1312 | /* | ||
1313 | * 16-bit Thumb data-processing instructions | ||
1314 | * 0100 00xx xxxx xxxx | ||
1315 | */ | ||
1316 | |||
1317 | /* TST (register) 0100 0010 00xx xxxx */ | ||
1318 | DECODE_EMULATE (0xffc0, 0x4200, t16_emulate_loregs_rwflags), | ||
1319 | /* CMP (register) 0100 0010 10xx xxxx */ | ||
1320 | /* CMN (register) 0100 0010 11xx xxxx */ | ||
1321 | DECODE_EMULATE (0xff80, 0x4280, t16_emulate_loregs_rwflags), | ||
1322 | /* AND (register) 0100 0000 00xx xxxx */ | ||
1323 | /* EOR (register) 0100 0000 01xx xxxx */ | ||
1324 | /* LSL (register) 0100 0000 10xx xxxx */ | ||
1325 | /* LSR (register) 0100 0000 11xx xxxx */ | ||
1326 | /* ASR (register) 0100 0001 00xx xxxx */ | ||
1327 | /* ADC (register) 0100 0001 01xx xxxx */ | ||
1328 | /* SBC (register) 0100 0001 10xx xxxx */ | ||
1329 | /* ROR (register) 0100 0001 11xx xxxx */ | ||
1330 | /* RSB (immediate) 0100 0010 01xx xxxx */ | ||
1331 | /* ORR (register) 0100 0011 00xx xxxx */ | ||
1332 | /* MUL 0100 0011 00xx xxxx */ | ||
1333 | /* BIC (register) 0100 0011 10xx xxxx */ | ||
1334 | /* MVN (register) 0100 0011 10xx xxxx */ | ||
1335 | DECODE_EMULATE (0xfc00, 0x4000, t16_emulate_loregs_noitrwflags), | ||
1336 | |||
1337 | /* | ||
1338 | * Special data instructions and branch and exchange | ||
1339 | * 0100 01xx xxxx xxxx | ||
1340 | */ | ||
1341 | |||
1342 | /* BLX pc 0100 0111 1111 1xxx */ | ||
1343 | DECODE_REJECT (0xfff8, 0x47f8), | ||
1344 | |||
1345 | /* BX (register) 0100 0111 0xxx xxxx */ | ||
1346 | /* BLX (register) 0100 0111 1xxx xxxx */ | ||
1347 | DECODE_SIMULATE (0xff00, 0x4700, t16_simulate_bxblx), | ||
1348 | |||
1349 | /* ADD pc, pc 0100 0100 1111 1111 */ | ||
1350 | DECODE_REJECT (0xffff, 0x44ff), | ||
1351 | |||
1352 | /* ADD (register) 0100 0100 xxxx xxxx */ | ||
1353 | /* CMP (register) 0100 0101 xxxx xxxx */ | ||
1354 | /* MOV (register) 0100 0110 xxxx xxxx */ | ||
1355 | DECODE_CUSTOM (0xfc00, 0x4400, t16_decode_hiregs), | ||
1356 | |||
1357 | /* | ||
1358 | * Load from Literal Pool | ||
1359 | * LDR (literal) 0100 1xxx xxxx xxxx | ||
1360 | */ | ||
1361 | DECODE_SIMULATE (0xf800, 0x4800, t16_simulate_ldr_literal), | ||
1362 | |||
1363 | /* | ||
1364 | * 16-bit Thumb Load/store instructions | ||
1365 | * 0101 xxxx xxxx xxxx | ||
1366 | * 011x xxxx xxxx xxxx | ||
1367 | * 100x xxxx xxxx xxxx | ||
1368 | */ | ||
1369 | |||
1370 | /* STR (register) 0101 000x xxxx xxxx */ | ||
1371 | /* STRH (register) 0101 001x xxxx xxxx */ | ||
1372 | /* STRB (register) 0101 010x xxxx xxxx */ | ||
1373 | /* LDRSB (register) 0101 011x xxxx xxxx */ | ||
1374 | /* LDR (register) 0101 100x xxxx xxxx */ | ||
1375 | /* LDRH (register) 0101 101x xxxx xxxx */ | ||
1376 | /* LDRB (register) 0101 110x xxxx xxxx */ | ||
1377 | /* LDRSH (register) 0101 111x xxxx xxxx */ | ||
1378 | /* STR (immediate, Thumb) 0110 0xxx xxxx xxxx */ | ||
1379 | /* LDR (immediate, Thumb) 0110 1xxx xxxx xxxx */ | ||
1380 | /* STRB (immediate, Thumb) 0111 0xxx xxxx xxxx */ | ||
1381 | /* LDRB (immediate, Thumb) 0111 1xxx xxxx xxxx */ | ||
1382 | DECODE_EMULATE (0xc000, 0x4000, t16_emulate_loregs_rwflags), | ||
1383 | /* STRH (immediate, Thumb) 1000 0xxx xxxx xxxx */ | ||
1384 | /* LDRH (immediate, Thumb) 1000 1xxx xxxx xxxx */ | ||
1385 | DECODE_EMULATE (0xf000, 0x8000, t16_emulate_loregs_rwflags), | ||
1386 | /* STR (immediate, Thumb) 1001 0xxx xxxx xxxx */ | ||
1387 | /* LDR (immediate, Thumb) 1001 1xxx xxxx xxxx */ | ||
1388 | DECODE_SIMULATE (0xf000, 0x9000, t16_simulate_ldrstr_sp_relative), | ||
1389 | |||
1390 | /* | ||
1391 | * Generate PC-/SP-relative address | ||
1392 | * ADR (literal) 1010 0xxx xxxx xxxx | ||
1393 | * ADD (SP plus immediate) 1010 1xxx xxxx xxxx | ||
1394 | */ | ||
1395 | DECODE_SIMULATE (0xf000, 0xa000, t16_simulate_reladr), | ||
1396 | |||
1397 | /* | ||
1398 | * Miscellaneous 16-bit instructions | ||
1399 | * 1011 xxxx xxxx xxxx | ||
1400 | */ | ||
1401 | DECODE_TABLE (0xf000, 0xb000, t16_table_1011), | ||
1402 | |||
1403 | /* STM 1100 0xxx xxxx xxxx */ | ||
1404 | /* LDM 1100 1xxx xxxx xxxx */ | ||
1405 | DECODE_EMULATE (0xf000, 0xc000, t16_emulate_loregs_rwflags), | ||
1406 | |||
1407 | /* | ||
1408 | * Conditional branch, and Supervisor Call | ||
1409 | */ | ||
1410 | |||
1411 | /* Permanently UNDEFINED 1101 1110 xxxx xxxx */ | ||
1412 | /* SVC 1101 1111 xxxx xxxx */ | ||
1413 | DECODE_REJECT (0xfe00, 0xde00), | ||
1414 | |||
1415 | /* Conditional branch 1101 xxxx xxxx xxxx */ | ||
1416 | DECODE_CUSTOM (0xf000, 0xd000, t16_decode_cond_branch), | ||
1417 | |||
1418 | /* | ||
1419 | * Unconditional branch | ||
1420 | * B 1110 0xxx xxxx xxxx | ||
1421 | */ | ||
1422 | DECODE_SIMULATE (0xf800, 0xe000, t16_simulate_branch), | ||
1423 | |||
1424 | DECODE_END | ||
1425 | }; | ||
1426 | |||
1427 | static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) | ||
1428 | { | ||
1429 | if (unlikely(in_it_block(cpsr))) | ||
1430 | return kprobe_condition_checks[current_cond(cpsr)](cpsr); | ||
1431 | return true; | ||
1432 | } | ||
1433 | |||
1434 | static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
1435 | { | ||
1436 | regs->ARM_pc += 2; | ||
1437 | p->ainsn.insn_handler(p, regs); | ||
1438 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | ||
1439 | } | ||
1440 | |||
1441 | static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) | ||
1442 | { | ||
1443 | regs->ARM_pc += 4; | ||
1444 | p->ainsn.insn_handler(p, regs); | ||
1445 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | ||
1446 | } | ||
1447 | |||
1448 | enum kprobe_insn __kprobes | ||
1449 | thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1450 | { | ||
1451 | asi->insn_singlestep = thumb16_singlestep; | ||
1452 | asi->insn_check_cc = thumb_check_cc; | ||
1453 | return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); | ||
1454 | } | ||
1455 | |||
1456 | enum kprobe_insn __kprobes | ||
1457 | thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | ||
1458 | { | ||
1459 | asi->insn_singlestep = thumb32_singlestep; | ||
1460 | asi->insn_check_cc = thumb_check_cc; | ||
1461 | return kprobe_decode_insn(insn, asi, kprobe_decode_thumb32_table, true); | ||
1462 | } | ||
diff --git a/arch/arm/kernel/kprobes.c b/arch/arm/kernel/kprobes.c index 1656c87501c0..129c1163248b 100644 --- a/arch/arm/kernel/kprobes.c +++ b/arch/arm/kernel/kprobes.c | |||
@@ -28,14 +28,16 @@ | |||
28 | #include <asm/traps.h> | 28 | #include <asm/traps.h> |
29 | #include <asm/cacheflush.h> | 29 | #include <asm/cacheflush.h> |
30 | 30 | ||
31 | #include "kprobes.h" | ||
32 | |||
31 | #define MIN_STACK_SIZE(addr) \ | 33 | #define MIN_STACK_SIZE(addr) \ |
32 | min((unsigned long)MAX_STACK_SIZE, \ | 34 | min((unsigned long)MAX_STACK_SIZE, \ |
33 | (unsigned long)current_thread_info() + THREAD_START_SP - (addr)) | 35 | (unsigned long)current_thread_info() + THREAD_START_SP - (addr)) |
34 | 36 | ||
35 | #define flush_insns(addr, cnt) \ | 37 | #define flush_insns(addr, size) \ |
36 | flush_icache_range((unsigned long)(addr), \ | 38 | flush_icache_range((unsigned long)(addr), \ |
37 | (unsigned long)(addr) + \ | 39 | (unsigned long)(addr) + \ |
38 | sizeof(kprobe_opcode_t) * (cnt)) | 40 | (size)) |
39 | 41 | ||
40 | /* Used as a marker in ARM_pc to note when we're in a jprobe. */ | 42 | /* Used as a marker in ARM_pc to note when we're in a jprobe. */ |
41 | #define JPROBE_MAGIC_ADDR 0xffffffff | 43 | #define JPROBE_MAGIC_ADDR 0xffffffff |
@@ -49,16 +51,35 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
49 | kprobe_opcode_t insn; | 51 | kprobe_opcode_t insn; |
50 | kprobe_opcode_t tmp_insn[MAX_INSN_SIZE]; | 52 | kprobe_opcode_t tmp_insn[MAX_INSN_SIZE]; |
51 | unsigned long addr = (unsigned long)p->addr; | 53 | unsigned long addr = (unsigned long)p->addr; |
54 | bool thumb; | ||
55 | kprobe_decode_insn_t *decode_insn; | ||
52 | int is; | 56 | int is; |
53 | 57 | ||
54 | if (addr & 0x3 || in_exception_text(addr)) | 58 | if (in_exception_text(addr)) |
55 | return -EINVAL; | 59 | return -EINVAL; |
56 | 60 | ||
61 | #ifdef CONFIG_THUMB2_KERNEL | ||
62 | thumb = true; | ||
63 | addr &= ~1; /* Bit 0 would normally be set to indicate Thumb code */ | ||
64 | insn = ((u16 *)addr)[0]; | ||
65 | if (is_wide_instruction(insn)) { | ||
66 | insn <<= 16; | ||
67 | insn |= ((u16 *)addr)[1]; | ||
68 | decode_insn = thumb32_kprobe_decode_insn; | ||
69 | } else | ||
70 | decode_insn = thumb16_kprobe_decode_insn; | ||
71 | #else /* !CONFIG_THUMB2_KERNEL */ | ||
72 | thumb = false; | ||
73 | if (addr & 0x3) | ||
74 | return -EINVAL; | ||
57 | insn = *p->addr; | 75 | insn = *p->addr; |
76 | decode_insn = arm_kprobe_decode_insn; | ||
77 | #endif | ||
78 | |||
58 | p->opcode = insn; | 79 | p->opcode = insn; |
59 | p->ainsn.insn = tmp_insn; | 80 | p->ainsn.insn = tmp_insn; |
60 | 81 | ||
61 | switch (arm_kprobe_decode_insn(insn, &p->ainsn)) { | 82 | switch ((*decode_insn)(insn, &p->ainsn)) { |
62 | case INSN_REJECTED: /* not supported */ | 83 | case INSN_REJECTED: /* not supported */ |
63 | return -EINVAL; | 84 | return -EINVAL; |
64 | 85 | ||
@@ -68,7 +89,10 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
68 | return -ENOMEM; | 89 | return -ENOMEM; |
69 | for (is = 0; is < MAX_INSN_SIZE; ++is) | 90 | for (is = 0; is < MAX_INSN_SIZE; ++is) |
70 | p->ainsn.insn[is] = tmp_insn[is]; | 91 | p->ainsn.insn[is] = tmp_insn[is]; |
71 | flush_insns(p->ainsn.insn, MAX_INSN_SIZE); | 92 | flush_insns(p->ainsn.insn, |
93 | sizeof(p->ainsn.insn[0]) * MAX_INSN_SIZE); | ||
94 | p->ainsn.insn_fn = (kprobe_insn_fn_t *) | ||
95 | ((uintptr_t)p->ainsn.insn | thumb); | ||
72 | break; | 96 | break; |
73 | 97 | ||
74 | case INSN_GOOD_NO_SLOT: /* instruction doesn't need insn slot */ | 98 | case INSN_GOOD_NO_SLOT: /* instruction doesn't need insn slot */ |
@@ -79,24 +103,88 @@ int __kprobes arch_prepare_kprobe(struct kprobe *p) | |||
79 | return 0; | 103 | return 0; |
80 | } | 104 | } |
81 | 105 | ||
106 | #ifdef CONFIG_THUMB2_KERNEL | ||
107 | |||
108 | /* | ||
109 | * For a 32-bit Thumb breakpoint spanning two memory words we need to take | ||
110 | * special precautions to insert the breakpoint atomically, especially on SMP | ||
111 | * systems. This is achieved by calling this arming function using stop_machine. | ||
112 | */ | ||
113 | static int __kprobes set_t32_breakpoint(void *addr) | ||
114 | { | ||
115 | ((u16 *)addr)[0] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION >> 16; | ||
116 | ((u16 *)addr)[1] = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION & 0xffff; | ||
117 | flush_insns(addr, 2*sizeof(u16)); | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | void __kprobes arch_arm_kprobe(struct kprobe *p) | ||
122 | { | ||
123 | uintptr_t addr = (uintptr_t)p->addr & ~1; /* Remove any Thumb flag */ | ||
124 | |||
125 | if (!is_wide_instruction(p->opcode)) { | ||
126 | *(u16 *)addr = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION; | ||
127 | flush_insns(addr, sizeof(u16)); | ||
128 | } else if (addr & 2) { | ||
129 | /* A 32-bit instruction spanning two words needs special care */ | ||
130 | stop_machine(set_t32_breakpoint, (void *)addr, &cpu_online_map); | ||
131 | } else { | ||
132 | /* Word aligned 32-bit instruction can be written atomically */ | ||
133 | u32 bkp = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION; | ||
134 | #ifndef __ARMEB__ /* Swap halfwords for little-endian */ | ||
135 | bkp = (bkp >> 16) | (bkp << 16); | ||
136 | #endif | ||
137 | *(u32 *)addr = bkp; | ||
138 | flush_insns(addr, sizeof(u32)); | ||
139 | } | ||
140 | } | ||
141 | |||
142 | #else /* !CONFIG_THUMB2_KERNEL */ | ||
143 | |||
82 | void __kprobes arch_arm_kprobe(struct kprobe *p) | 144 | void __kprobes arch_arm_kprobe(struct kprobe *p) |
83 | { | 145 | { |
84 | *p->addr = KPROBE_BREAKPOINT_INSTRUCTION; | 146 | kprobe_opcode_t insn = p->opcode; |
85 | flush_insns(p->addr, 1); | 147 | kprobe_opcode_t brkp = KPROBE_ARM_BREAKPOINT_INSTRUCTION; |
148 | if (insn >= 0xe0000000) | ||
149 | brkp |= 0xe0000000; /* Unconditional instruction */ | ||
150 | else | ||
151 | brkp |= insn & 0xf0000000; /* Copy condition from insn */ | ||
152 | *p->addr = brkp; | ||
153 | flush_insns(p->addr, sizeof(p->addr[0])); | ||
86 | } | 154 | } |
87 | 155 | ||
156 | #endif /* !CONFIG_THUMB2_KERNEL */ | ||
157 | |||
88 | /* | 158 | /* |
89 | * The actual disarming is done here on each CPU and synchronized using | 159 | * The actual disarming is done here on each CPU and synchronized using |
90 | * stop_machine. This synchronization is necessary on SMP to avoid removing | 160 | * stop_machine. This synchronization is necessary on SMP to avoid removing |
91 | * a probe between the moment the 'Undefined Instruction' exception is raised | 161 | * a probe between the moment the 'Undefined Instruction' exception is raised |
92 | * and the moment the exception handler reads the faulting instruction from | 162 | * and the moment the exception handler reads the faulting instruction from |
93 | * memory. | 163 | * memory. It is also needed to atomically set the two half-words of a 32-bit |
164 | * Thumb breakpoint. | ||
94 | */ | 165 | */ |
95 | int __kprobes __arch_disarm_kprobe(void *p) | 166 | int __kprobes __arch_disarm_kprobe(void *p) |
96 | { | 167 | { |
97 | struct kprobe *kp = p; | 168 | struct kprobe *kp = p; |
169 | #ifdef CONFIG_THUMB2_KERNEL | ||
170 | u16 *addr = (u16 *)((uintptr_t)kp->addr & ~1); | ||
171 | kprobe_opcode_t insn = kp->opcode; | ||
172 | unsigned int len; | ||
173 | |||
174 | if (is_wide_instruction(insn)) { | ||
175 | ((u16 *)addr)[0] = insn>>16; | ||
176 | ((u16 *)addr)[1] = insn; | ||
177 | len = 2*sizeof(u16); | ||
178 | } else { | ||
179 | ((u16 *)addr)[0] = insn; | ||
180 | len = sizeof(u16); | ||
181 | } | ||
182 | flush_insns(addr, len); | ||
183 | |||
184 | #else /* !CONFIG_THUMB2_KERNEL */ | ||
98 | *kp->addr = kp->opcode; | 185 | *kp->addr = kp->opcode; |
99 | flush_insns(kp->addr, 1); | 186 | flush_insns(kp->addr, sizeof(kp->addr[0])); |
187 | #endif | ||
100 | return 0; | 188 | return 0; |
101 | } | 189 | } |
102 | 190 | ||
@@ -130,12 +218,24 @@ static void __kprobes set_current_kprobe(struct kprobe *p) | |||
130 | __get_cpu_var(current_kprobe) = p; | 218 | __get_cpu_var(current_kprobe) = p; |
131 | } | 219 | } |
132 | 220 | ||
133 | static void __kprobes singlestep(struct kprobe *p, struct pt_regs *regs, | 221 | static void __kprobes |
134 | struct kprobe_ctlblk *kcb) | 222 | singlestep_skip(struct kprobe *p, struct pt_regs *regs) |
135 | { | 223 | { |
224 | #ifdef CONFIG_THUMB2_KERNEL | ||
225 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | ||
226 | if (is_wide_instruction(p->opcode)) | ||
227 | regs->ARM_pc += 4; | ||
228 | else | ||
229 | regs->ARM_pc += 2; | ||
230 | #else | ||
136 | regs->ARM_pc += 4; | 231 | regs->ARM_pc += 4; |
137 | if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) | 232 | #endif |
138 | p->ainsn.insn_handler(p, regs); | 233 | } |
234 | |||
235 | static inline void __kprobes | ||
236 | singlestep(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb) | ||
237 | { | ||
238 | p->ainsn.insn_singlestep(p, regs); | ||
139 | } | 239 | } |
140 | 240 | ||
141 | /* | 241 | /* |
@@ -149,11 +249,23 @@ void __kprobes kprobe_handler(struct pt_regs *regs) | |||
149 | { | 249 | { |
150 | struct kprobe *p, *cur; | 250 | struct kprobe *p, *cur; |
151 | struct kprobe_ctlblk *kcb; | 251 | struct kprobe_ctlblk *kcb; |
152 | kprobe_opcode_t *addr = (kprobe_opcode_t *)regs->ARM_pc; | ||
153 | 252 | ||
154 | kcb = get_kprobe_ctlblk(); | 253 | kcb = get_kprobe_ctlblk(); |
155 | cur = kprobe_running(); | 254 | cur = kprobe_running(); |
156 | p = get_kprobe(addr); | 255 | |
256 | #ifdef CONFIG_THUMB2_KERNEL | ||
257 | /* | ||
258 | * First look for a probe which was registered using an address with | ||
259 | * bit 0 set, this is the usual situation for pointers to Thumb code. | ||
260 | * If not found, fallback to looking for one with bit 0 clear. | ||
261 | */ | ||
262 | p = get_kprobe((kprobe_opcode_t *)(regs->ARM_pc | 1)); | ||
263 | if (!p) | ||
264 | p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc); | ||
265 | |||
266 | #else /* ! CONFIG_THUMB2_KERNEL */ | ||
267 | p = get_kprobe((kprobe_opcode_t *)regs->ARM_pc); | ||
268 | #endif | ||
157 | 269 | ||
158 | if (p) { | 270 | if (p) { |
159 | if (cur) { | 271 | if (cur) { |
@@ -173,7 +285,8 @@ void __kprobes kprobe_handler(struct pt_regs *regs) | |||
173 | /* impossible cases */ | 285 | /* impossible cases */ |
174 | BUG(); | 286 | BUG(); |
175 | } | 287 | } |
176 | } else { | 288 | } else if (p->ainsn.insn_check_cc(regs->ARM_cpsr)) { |
289 | /* Probe hit and conditional execution check ok. */ | ||
177 | set_current_kprobe(p); | 290 | set_current_kprobe(p); |
178 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; | 291 | kcb->kprobe_status = KPROBE_HIT_ACTIVE; |
179 | 292 | ||
@@ -193,6 +306,13 @@ void __kprobes kprobe_handler(struct pt_regs *regs) | |||
193 | } | 306 | } |
194 | reset_current_kprobe(); | 307 | reset_current_kprobe(); |
195 | } | 308 | } |
309 | } else { | ||
310 | /* | ||
311 | * Probe hit but conditional execution check failed, | ||
312 | * so just skip the instruction and continue as if | ||
313 | * nothing had happened. | ||
314 | */ | ||
315 | singlestep_skip(p, regs); | ||
196 | } | 316 | } |
197 | } else if (cur) { | 317 | } else if (cur) { |
198 | /* We probably hit a jprobe. Call its break handler. */ | 318 | /* We probably hit a jprobe. Call its break handler. */ |
@@ -300,7 +420,11 @@ void __naked __kprobes kretprobe_trampoline(void) | |||
300 | "bl trampoline_handler \n\t" | 420 | "bl trampoline_handler \n\t" |
301 | "mov lr, r0 \n\t" | 421 | "mov lr, r0 \n\t" |
302 | "ldmia sp!, {r0 - r11} \n\t" | 422 | "ldmia sp!, {r0 - r11} \n\t" |
423 | #ifdef CONFIG_THUMB2_KERNEL | ||
424 | "bx lr \n\t" | ||
425 | #else | ||
303 | "mov pc, lr \n\t" | 426 | "mov pc, lr \n\t" |
427 | #endif | ||
304 | : : : "memory"); | 428 | : : : "memory"); |
305 | } | 429 | } |
306 | 430 | ||
@@ -378,11 +502,22 @@ int __kprobes setjmp_pre_handler(struct kprobe *p, struct pt_regs *regs) | |||
378 | struct jprobe *jp = container_of(p, struct jprobe, kp); | 502 | struct jprobe *jp = container_of(p, struct jprobe, kp); |
379 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); | 503 | struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); |
380 | long sp_addr = regs->ARM_sp; | 504 | long sp_addr = regs->ARM_sp; |
505 | long cpsr; | ||
381 | 506 | ||
382 | kcb->jprobe_saved_regs = *regs; | 507 | kcb->jprobe_saved_regs = *regs; |
383 | memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr)); | 508 | memcpy(kcb->jprobes_stack, (void *)sp_addr, MIN_STACK_SIZE(sp_addr)); |
384 | regs->ARM_pc = (long)jp->entry; | 509 | regs->ARM_pc = (long)jp->entry; |
385 | regs->ARM_cpsr |= PSR_I_BIT; | 510 | |
511 | cpsr = regs->ARM_cpsr | PSR_I_BIT; | ||
512 | #ifdef CONFIG_THUMB2_KERNEL | ||
513 | /* Set correct Thumb state in cpsr */ | ||
514 | if (regs->ARM_pc & 1) | ||
515 | cpsr |= PSR_T_BIT; | ||
516 | else | ||
517 | cpsr &= ~PSR_T_BIT; | ||
518 | #endif | ||
519 | regs->ARM_cpsr = cpsr; | ||
520 | |||
386 | preempt_disable(); | 521 | preempt_disable(); |
387 | return 1; | 522 | return 1; |
388 | } | 523 | } |
@@ -404,7 +539,12 @@ void __kprobes jprobe_return(void) | |||
404 | * This is to prevent any simulated instruction from writing | 539 | * This is to prevent any simulated instruction from writing |
405 | * over the regs when they are accessing the stack. | 540 | * over the regs when they are accessing the stack. |
406 | */ | 541 | */ |
542 | #ifdef CONFIG_THUMB2_KERNEL | ||
543 | "sub r0, %0, %1 \n\t" | ||
544 | "mov sp, r0 \n\t" | ||
545 | #else | ||
407 | "sub sp, %0, %1 \n\t" | 546 | "sub sp, %0, %1 \n\t" |
547 | #endif | ||
408 | "ldr r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t" | 548 | "ldr r0, ="__stringify(JPROBE_MAGIC_ADDR)"\n\t" |
409 | "str %0, [sp, %2] \n\t" | 549 | "str %0, [sp, %2] \n\t" |
410 | "str r0, [sp, %3] \n\t" | 550 | "str r0, [sp, %3] \n\t" |
@@ -415,15 +555,28 @@ void __kprobes jprobe_return(void) | |||
415 | * Return to the context saved by setjmp_pre_handler | 555 | * Return to the context saved by setjmp_pre_handler |
416 | * and restored by longjmp_break_handler. | 556 | * and restored by longjmp_break_handler. |
417 | */ | 557 | */ |
558 | #ifdef CONFIG_THUMB2_KERNEL | ||
559 | "ldr lr, [sp, %2] \n\t" /* lr = saved sp */ | ||
560 | "ldrd r0, r1, [sp, %5] \n\t" /* r0,r1 = saved lr,pc */ | ||
561 | "ldr r2, [sp, %4] \n\t" /* r2 = saved psr */ | ||
562 | "stmdb lr!, {r0, r1, r2} \n\t" /* push saved lr and */ | ||
563 | /* rfe context */ | ||
564 | "ldmia sp, {r0 - r12} \n\t" | ||
565 | "mov sp, lr \n\t" | ||
566 | "ldr lr, [sp], #4 \n\t" | ||
567 | "rfeia sp! \n\t" | ||
568 | #else | ||
418 | "ldr r0, [sp, %4] \n\t" | 569 | "ldr r0, [sp, %4] \n\t" |
419 | "msr cpsr_cxsf, r0 \n\t" | 570 | "msr cpsr_cxsf, r0 \n\t" |
420 | "ldmia sp, {r0 - pc} \n\t" | 571 | "ldmia sp, {r0 - pc} \n\t" |
572 | #endif | ||
421 | : | 573 | : |
422 | : "r" (kcb->jprobe_saved_regs.ARM_sp), | 574 | : "r" (kcb->jprobe_saved_regs.ARM_sp), |
423 | "I" (sizeof(struct pt_regs) * 2), | 575 | "I" (sizeof(struct pt_regs) * 2), |
424 | "J" (offsetof(struct pt_regs, ARM_sp)), | 576 | "J" (offsetof(struct pt_regs, ARM_sp)), |
425 | "J" (offsetof(struct pt_regs, ARM_pc)), | 577 | "J" (offsetof(struct pt_regs, ARM_pc)), |
426 | "J" (offsetof(struct pt_regs, ARM_cpsr)) | 578 | "J" (offsetof(struct pt_regs, ARM_cpsr)), |
579 | "J" (offsetof(struct pt_regs, ARM_lr)) | ||
427 | : "memory", "cc"); | 580 | : "memory", "cc"); |
428 | } | 581 | } |
429 | 582 | ||
@@ -460,17 +613,44 @@ int __kprobes arch_trampoline_kprobe(struct kprobe *p) | |||
460 | return 0; | 613 | return 0; |
461 | } | 614 | } |
462 | 615 | ||
463 | static struct undef_hook kprobes_break_hook = { | 616 | #ifdef CONFIG_THUMB2_KERNEL |
617 | |||
618 | static struct undef_hook kprobes_thumb16_break_hook = { | ||
619 | .instr_mask = 0xffff, | ||
620 | .instr_val = KPROBE_THUMB16_BREAKPOINT_INSTRUCTION, | ||
621 | .cpsr_mask = MODE_MASK, | ||
622 | .cpsr_val = SVC_MODE, | ||
623 | .fn = kprobe_trap_handler, | ||
624 | }; | ||
625 | |||
626 | static struct undef_hook kprobes_thumb32_break_hook = { | ||
464 | .instr_mask = 0xffffffff, | 627 | .instr_mask = 0xffffffff, |
465 | .instr_val = KPROBE_BREAKPOINT_INSTRUCTION, | 628 | .instr_val = KPROBE_THUMB32_BREAKPOINT_INSTRUCTION, |
466 | .cpsr_mask = MODE_MASK, | 629 | .cpsr_mask = MODE_MASK, |
467 | .cpsr_val = SVC_MODE, | 630 | .cpsr_val = SVC_MODE, |
468 | .fn = kprobe_trap_handler, | 631 | .fn = kprobe_trap_handler, |
469 | }; | 632 | }; |
470 | 633 | ||
634 | #else /* !CONFIG_THUMB2_KERNEL */ | ||
635 | |||
636 | static struct undef_hook kprobes_arm_break_hook = { | ||
637 | .instr_mask = 0x0fffffff, | ||
638 | .instr_val = KPROBE_ARM_BREAKPOINT_INSTRUCTION, | ||
639 | .cpsr_mask = MODE_MASK, | ||
640 | .cpsr_val = SVC_MODE, | ||
641 | .fn = kprobe_trap_handler, | ||
642 | }; | ||
643 | |||
644 | #endif /* !CONFIG_THUMB2_KERNEL */ | ||
645 | |||
471 | int __init arch_init_kprobes() | 646 | int __init arch_init_kprobes() |
472 | { | 647 | { |
473 | arm_kprobe_decode_init(); | 648 | arm_kprobe_decode_init(); |
474 | register_undef_hook(&kprobes_break_hook); | 649 | #ifdef CONFIG_THUMB2_KERNEL |
650 | register_undef_hook(&kprobes_thumb16_break_hook); | ||
651 | register_undef_hook(&kprobes_thumb32_break_hook); | ||
652 | #else | ||
653 | register_undef_hook(&kprobes_arm_break_hook); | ||
654 | #endif | ||
475 | return 0; | 655 | return 0; |
476 | } | 656 | } |
diff --git a/arch/arm/kernel/kprobes.h b/arch/arm/kernel/kprobes.h new file mode 100644 index 000000000000..a6aeda0a6c7f --- /dev/null +++ b/arch/arm/kernel/kprobes.h | |||
@@ -0,0 +1,420 @@ | |||
1 | /* | ||
2 | * arch/arm/kernel/kprobes.h | ||
3 | * | ||
4 | * Copyright (C) 2011 Jon Medhurst <tixy@yxit.co.uk>. | ||
5 | * | ||
6 | * Some contents moved here from arch/arm/include/asm/kprobes.h 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 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | */ | ||
18 | |||
19 | #ifndef _ARM_KERNEL_KPROBES_H | ||
20 | #define _ARM_KERNEL_KPROBES_H | ||
21 | |||
22 | /* | ||
23 | * These undefined instructions must be unique and | ||
24 | * reserved solely for kprobes' use. | ||
25 | */ | ||
26 | #define KPROBE_ARM_BREAKPOINT_INSTRUCTION 0x07f001f8 | ||
27 | #define KPROBE_THUMB16_BREAKPOINT_INSTRUCTION 0xde18 | ||
28 | #define KPROBE_THUMB32_BREAKPOINT_INSTRUCTION 0xf7f0a018 | ||
29 | |||
30 | |||
31 | enum kprobe_insn { | ||
32 | INSN_REJECTED, | ||
33 | INSN_GOOD, | ||
34 | INSN_GOOD_NO_SLOT | ||
35 | }; | ||
36 | |||
37 | typedef enum kprobe_insn (kprobe_decode_insn_t)(kprobe_opcode_t, | ||
38 | struct arch_specific_insn *); | ||
39 | |||
40 | #ifdef CONFIG_THUMB2_KERNEL | ||
41 | |||
42 | enum kprobe_insn thumb16_kprobe_decode_insn(kprobe_opcode_t, | ||
43 | struct arch_specific_insn *); | ||
44 | enum kprobe_insn thumb32_kprobe_decode_insn(kprobe_opcode_t, | ||
45 | struct arch_specific_insn *); | ||
46 | |||
47 | #else /* !CONFIG_THUMB2_KERNEL */ | ||
48 | |||
49 | enum kprobe_insn arm_kprobe_decode_insn(kprobe_opcode_t, | ||
50 | struct arch_specific_insn *); | ||
51 | #endif | ||
52 | |||
53 | void __init arm_kprobe_decode_init(void); | ||
54 | |||
55 | extern kprobe_check_cc * const kprobe_condition_checks[16]; | ||
56 | |||
57 | |||
58 | #if __LINUX_ARM_ARCH__ >= 7 | ||
59 | |||
60 | /* str_pc_offset is architecturally defined from ARMv7 onwards */ | ||
61 | #define str_pc_offset 8 | ||
62 | #define find_str_pc_offset() | ||
63 | |||
64 | #else /* __LINUX_ARM_ARCH__ < 7 */ | ||
65 | |||
66 | /* We need a run-time check to determine str_pc_offset */ | ||
67 | extern int str_pc_offset; | ||
68 | void __init find_str_pc_offset(void); | ||
69 | |||
70 | #endif | ||
71 | |||
72 | |||
73 | /* | ||
74 | * Update ITSTATE after normal execution of an IT block instruction. | ||
75 | * | ||
76 | * The 8 IT state bits are split into two parts in CPSR: | ||
77 | * ITSTATE<1:0> are in CPSR<26:25> | ||
78 | * ITSTATE<7:2> are in CPSR<15:10> | ||
79 | */ | ||
80 | static inline unsigned long it_advance(unsigned long cpsr) | ||
81 | { | ||
82 | if ((cpsr & 0x06000400) == 0) { | ||
83 | /* ITSTATE<2:0> == 0 means end of IT block, so clear IT state */ | ||
84 | cpsr &= ~PSR_IT_MASK; | ||
85 | } else { | ||
86 | /* We need to shift left ITSTATE<4:0> */ | ||
87 | const unsigned long mask = 0x06001c00; /* Mask ITSTATE<4:0> */ | ||
88 | unsigned long it = cpsr & mask; | ||
89 | it <<= 1; | ||
90 | it |= it >> (27 - 10); /* Carry ITSTATE<2> to correct place */ | ||
91 | it &= mask; | ||
92 | cpsr &= ~mask; | ||
93 | cpsr |= it; | ||
94 | } | ||
95 | return cpsr; | ||
96 | } | ||
97 | |||
98 | static inline void __kprobes bx_write_pc(long pcv, struct pt_regs *regs) | ||
99 | { | ||
100 | long cpsr = regs->ARM_cpsr; | ||
101 | if (pcv & 0x1) { | ||
102 | cpsr |= PSR_T_BIT; | ||
103 | pcv &= ~0x1; | ||
104 | } else { | ||
105 | cpsr &= ~PSR_T_BIT; | ||
106 | pcv &= ~0x2; /* Avoid UNPREDICTABLE address allignment */ | ||
107 | } | ||
108 | regs->ARM_cpsr = cpsr; | ||
109 | regs->ARM_pc = pcv; | ||
110 | } | ||
111 | |||
112 | |||
113 | #if __LINUX_ARM_ARCH__ >= 6 | ||
114 | |||
115 | /* Kernels built for >= ARMv6 should never run on <= ARMv5 hardware, so... */ | ||
116 | #define load_write_pc_interworks true | ||
117 | #define test_load_write_pc_interworking() | ||
118 | |||
119 | #else /* __LINUX_ARM_ARCH__ < 6 */ | ||
120 | |||
121 | /* We need run-time testing to determine if load_write_pc() should interwork. */ | ||
122 | extern bool load_write_pc_interworks; | ||
123 | void __init test_load_write_pc_interworking(void); | ||
124 | |||
125 | #endif | ||
126 | |||
127 | static inline void __kprobes load_write_pc(long pcv, struct pt_regs *regs) | ||
128 | { | ||
129 | if (load_write_pc_interworks) | ||
130 | bx_write_pc(pcv, regs); | ||
131 | else | ||
132 | regs->ARM_pc = pcv; | ||
133 | } | ||
134 | |||
135 | |||
136 | #if __LINUX_ARM_ARCH__ >= 7 | ||
137 | |||
138 | #define alu_write_pc_interworks true | ||
139 | #define test_alu_write_pc_interworking() | ||
140 | |||
141 | #elif __LINUX_ARM_ARCH__ <= 5 | ||
142 | |||
143 | /* Kernels built for <= ARMv5 should never run on >= ARMv6 hardware, so... */ | ||
144 | #define alu_write_pc_interworks false | ||
145 | #define test_alu_write_pc_interworking() | ||
146 | |||
147 | #else /* __LINUX_ARM_ARCH__ == 6 */ | ||
148 | |||
149 | /* We could be an ARMv6 binary on ARMv7 hardware so we need a run-time check. */ | ||
150 | extern bool alu_write_pc_interworks; | ||
151 | void __init test_alu_write_pc_interworking(void); | ||
152 | |||
153 | #endif /* __LINUX_ARM_ARCH__ == 6 */ | ||
154 | |||
155 | static inline void __kprobes alu_write_pc(long pcv, struct pt_regs *regs) | ||
156 | { | ||
157 | if (alu_write_pc_interworks) | ||
158 | bx_write_pc(pcv, regs); | ||
159 | else | ||
160 | regs->ARM_pc = pcv; | ||
161 | } | ||
162 | |||
163 | |||
164 | void __kprobes kprobe_simulate_nop(struct kprobe *p, struct pt_regs *regs); | ||
165 | void __kprobes kprobe_emulate_none(struct kprobe *p, struct pt_regs *regs); | ||
166 | |||
167 | enum kprobe_insn __kprobes | ||
168 | kprobe_decode_ldmstm(kprobe_opcode_t insn, struct arch_specific_insn *asi); | ||
169 | |||
170 | /* | ||
171 | * Test if load/store instructions writeback the address register. | ||
172 | * if P (bit 24) == 0 or W (bit 21) == 1 | ||
173 | */ | ||
174 | #define is_writeback(insn) ((insn ^ 0x01000000) & 0x01200000) | ||
175 | |||
176 | /* | ||
177 | * The following definitions and macros are used to build instruction | ||
178 | * decoding tables for use by kprobe_decode_insn. | ||
179 | * | ||
180 | * These tables are a concatenation of entries each of which consist of one of | ||
181 | * the decode_* structs. All of the fields in every type of decode structure | ||
182 | * are of the union type decode_item, therefore the entire decode table can be | ||
183 | * viewed as an array of these and declared like: | ||
184 | * | ||
185 | * static const union decode_item table_name[] = {}; | ||
186 | * | ||
187 | * In order to construct each entry in the table, macros are used to | ||
188 | * initialise a number of sequential decode_item values in a layout which | ||
189 | * matches the relevant struct. E.g. DECODE_SIMULATE initialise a struct | ||
190 | * decode_simulate by initialising four decode_item objects like this... | ||
191 | * | ||
192 | * {.bits = _type}, | ||
193 | * {.bits = _mask}, | ||
194 | * {.bits = _value}, | ||
195 | * {.handler = _handler}, | ||
196 | * | ||
197 | * Initialising a specified member of the union means that the compiler | ||
198 | * will produce a warning if the argument is of an incorrect type. | ||
199 | * | ||
200 | * Below is a list of each of the macros used to initialise entries and a | ||
201 | * description of the action performed when that entry is matched to an | ||
202 | * instruction. A match is found when (instruction & mask) == value. | ||
203 | * | ||
204 | * DECODE_TABLE(mask, value, table) | ||
205 | * Instruction decoding jumps to parsing the new sub-table 'table'. | ||
206 | * | ||
207 | * DECODE_CUSTOM(mask, value, decoder) | ||
208 | * The custom function 'decoder' is called to the complete decoding | ||
209 | * of an instruction. | ||
210 | * | ||
211 | * DECODE_SIMULATE(mask, value, handler) | ||
212 | * Set the probes instruction handler to 'handler', this will be used | ||
213 | * to simulate the instruction when the probe is hit. Decoding returns | ||
214 | * with INSN_GOOD_NO_SLOT. | ||
215 | * | ||
216 | * DECODE_EMULATE(mask, value, handler) | ||
217 | * Set the probes instruction handler to 'handler', this will be used | ||
218 | * to emulate the instruction when the probe is hit. The modified | ||
219 | * instruction (see below) is placed in the probes instruction slot so it | ||
220 | * may be called by the emulation code. Decoding returns with INSN_GOOD. | ||
221 | * | ||
222 | * DECODE_REJECT(mask, value) | ||
223 | * Instruction decoding fails with INSN_REJECTED | ||
224 | * | ||
225 | * DECODE_OR(mask, value) | ||
226 | * This allows the mask/value test of multiple table entries to be | ||
227 | * logically ORed. Once an 'or' entry is matched the decoding action to | ||
228 | * be performed is that of the next entry which isn't an 'or'. E.g. | ||
229 | * | ||
230 | * DECODE_OR (mask1, value1) | ||
231 | * DECODE_OR (mask2, value2) | ||
232 | * DECODE_SIMULATE (mask3, value3, simulation_handler) | ||
233 | * | ||
234 | * This means that if any of the three mask/value pairs match the | ||
235 | * instruction being decoded, then 'simulation_handler' will be used | ||
236 | * for it. | ||
237 | * | ||
238 | * Both the SIMULATE and EMULATE macros have a second form which take an | ||
239 | * additional 'regs' argument. | ||
240 | * | ||
241 | * DECODE_SIMULATEX(mask, value, handler, regs) | ||
242 | * DECODE_EMULATEX (mask, value, handler, regs) | ||
243 | * | ||
244 | * These are used to specify what kind of CPU register is encoded in each of the | ||
245 | * least significant 5 nibbles of the instruction being decoded. The regs value | ||
246 | * is specified using the REGS macro, this takes any of the REG_TYPE_* values | ||
247 | * from enum decode_reg_type as arguments; only the '*' part of the name is | ||
248 | * given. E.g. | ||
249 | * | ||
250 | * REGS(0, ANY, NOPC, 0, ANY) | ||
251 | * | ||
252 | * This indicates an instruction is encoded like: | ||
253 | * | ||
254 | * bits 19..16 ignore | ||
255 | * bits 15..12 any register allowed here | ||
256 | * bits 11.. 8 any register except PC allowed here | ||
257 | * bits 7.. 4 ignore | ||
258 | * bits 3.. 0 any register allowed here | ||
259 | * | ||
260 | * This register specification is checked after a decode table entry is found to | ||
261 | * match an instruction (through the mask/value test). Any invalid register then | ||
262 | * found in the instruction will cause decoding to fail with INSN_REJECTED. In | ||
263 | * the above example this would happen if bits 11..8 of the instruction were | ||
264 | * 1111, indicating R15 or PC. | ||
265 | * | ||
266 | * As well as checking for legal combinations of registers, this data is also | ||
267 | * used to modify the registers encoded in the instructions so that an | ||
268 | * emulation routines can use it. (See decode_regs() and INSN_NEW_BITS.) | ||
269 | * | ||
270 | * Here is a real example which matches ARM instructions of the form | ||
271 | * "AND <Rd>,<Rn>,<Rm>,<shift> <Rs>" | ||
272 | * | ||
273 | * DECODE_EMULATEX (0x0e000090, 0x00000010, emulate_rd12rn16rm0rs8_rwflags, | ||
274 | * REGS(ANY, ANY, NOPC, 0, ANY)), | ||
275 | * ^ ^ ^ ^ | ||
276 | * Rn Rd Rs Rm | ||
277 | * | ||
278 | * Decoding the instruction "AND R4, R5, R6, ASL R15" will be rejected because | ||
279 | * Rs == R15 | ||
280 | * | ||
281 | * Decoding the instruction "AND R4, R5, R6, ASL R7" will be accepted and the | ||
282 | * instruction will be modified to "AND R0, R2, R3, ASL R1" and then placed into | ||
283 | * the kprobes instruction slot. This can then be called later by the handler | ||
284 | * function emulate_rd12rn16rm0rs8_rwflags in order to simulate the instruction. | ||
285 | */ | ||
286 | |||
287 | enum decode_type { | ||
288 | DECODE_TYPE_END, | ||
289 | DECODE_TYPE_TABLE, | ||
290 | DECODE_TYPE_CUSTOM, | ||
291 | DECODE_TYPE_SIMULATE, | ||
292 | DECODE_TYPE_EMULATE, | ||
293 | DECODE_TYPE_OR, | ||
294 | DECODE_TYPE_REJECT, | ||
295 | NUM_DECODE_TYPES /* Must be last enum */ | ||
296 | }; | ||
297 | |||
298 | #define DECODE_TYPE_BITS 4 | ||
299 | #define DECODE_TYPE_MASK ((1 << DECODE_TYPE_BITS) - 1) | ||
300 | |||
301 | enum decode_reg_type { | ||
302 | REG_TYPE_NONE = 0, /* Not a register, ignore */ | ||
303 | REG_TYPE_ANY, /* Any register allowed */ | ||
304 | REG_TYPE_SAMEAS16, /* Register should be same as that at bits 19..16 */ | ||
305 | REG_TYPE_SP, /* Register must be SP */ | ||
306 | REG_TYPE_PC, /* Register must be PC */ | ||
307 | REG_TYPE_NOSP, /* Register must not be SP */ | ||
308 | REG_TYPE_NOSPPC, /* Register must not be SP or PC */ | ||
309 | REG_TYPE_NOPC, /* Register must not be PC */ | ||
310 | REG_TYPE_NOPCWB, /* No PC if load/store write-back flag also set */ | ||
311 | |||
312 | /* The following types are used when the encoding for PC indicates | ||
313 | * another instruction form. This distiction only matters for test | ||
314 | * case coverage checks. | ||
315 | */ | ||
316 | REG_TYPE_NOPCX, /* Register must not be PC */ | ||
317 | REG_TYPE_NOSPPCX, /* Register must not be SP or PC */ | ||
318 | |||
319 | /* Alias to allow '0' arg to be used in REGS macro. */ | ||
320 | REG_TYPE_0 = REG_TYPE_NONE | ||
321 | }; | ||
322 | |||
323 | #define REGS(r16, r12, r8, r4, r0) \ | ||
324 | ((REG_TYPE_##r16) << 16) + \ | ||
325 | ((REG_TYPE_##r12) << 12) + \ | ||
326 | ((REG_TYPE_##r8) << 8) + \ | ||
327 | ((REG_TYPE_##r4) << 4) + \ | ||
328 | (REG_TYPE_##r0) | ||
329 | |||
330 | union decode_item { | ||
331 | u32 bits; | ||
332 | const union decode_item *table; | ||
333 | kprobe_insn_handler_t *handler; | ||
334 | kprobe_decode_insn_t *decoder; | ||
335 | }; | ||
336 | |||
337 | |||
338 | #define DECODE_END \ | ||
339 | {.bits = DECODE_TYPE_END} | ||
340 | |||
341 | |||
342 | struct decode_header { | ||
343 | union decode_item type_regs; | ||
344 | union decode_item mask; | ||
345 | union decode_item value; | ||
346 | }; | ||
347 | |||
348 | #define DECODE_HEADER(_type, _mask, _value, _regs) \ | ||
349 | {.bits = (_type) | ((_regs) << DECODE_TYPE_BITS)}, \ | ||
350 | {.bits = (_mask)}, \ | ||
351 | {.bits = (_value)} | ||
352 | |||
353 | |||
354 | struct decode_table { | ||
355 | struct decode_header header; | ||
356 | union decode_item table; | ||
357 | }; | ||
358 | |||
359 | #define DECODE_TABLE(_mask, _value, _table) \ | ||
360 | DECODE_HEADER(DECODE_TYPE_TABLE, _mask, _value, 0), \ | ||
361 | {.table = (_table)} | ||
362 | |||
363 | |||
364 | struct decode_custom { | ||
365 | struct decode_header header; | ||
366 | union decode_item decoder; | ||
367 | }; | ||
368 | |||
369 | #define DECODE_CUSTOM(_mask, _value, _decoder) \ | ||
370 | DECODE_HEADER(DECODE_TYPE_CUSTOM, _mask, _value, 0), \ | ||
371 | {.decoder = (_decoder)} | ||
372 | |||
373 | |||
374 | struct decode_simulate { | ||
375 | struct decode_header header; | ||
376 | union decode_item handler; | ||
377 | }; | ||
378 | |||
379 | #define DECODE_SIMULATEX(_mask, _value, _handler, _regs) \ | ||
380 | DECODE_HEADER(DECODE_TYPE_SIMULATE, _mask, _value, _regs), \ | ||
381 | {.handler = (_handler)} | ||
382 | |||
383 | #define DECODE_SIMULATE(_mask, _value, _handler) \ | ||
384 | DECODE_SIMULATEX(_mask, _value, _handler, 0) | ||
385 | |||
386 | |||
387 | struct decode_emulate { | ||
388 | struct decode_header header; | ||
389 | union decode_item handler; | ||
390 | }; | ||
391 | |||
392 | #define DECODE_EMULATEX(_mask, _value, _handler, _regs) \ | ||
393 | DECODE_HEADER(DECODE_TYPE_EMULATE, _mask, _value, _regs), \ | ||
394 | {.handler = (_handler)} | ||
395 | |||
396 | #define DECODE_EMULATE(_mask, _value, _handler) \ | ||
397 | DECODE_EMULATEX(_mask, _value, _handler, 0) | ||
398 | |||
399 | |||
400 | struct decode_or { | ||
401 | struct decode_header header; | ||
402 | }; | ||
403 | |||
404 | #define DECODE_OR(_mask, _value) \ | ||
405 | DECODE_HEADER(DECODE_TYPE_OR, _mask, _value, 0) | ||
406 | |||
407 | |||
408 | struct decode_reject { | ||
409 | struct decode_header header; | ||
410 | }; | ||
411 | |||
412 | #define DECODE_REJECT(_mask, _value) \ | ||
413 | DECODE_HEADER(DECODE_TYPE_REJECT, _mask, _value, 0) | ||
414 | |||
415 | |||
416 | int kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi, | ||
417 | const union decode_item *table, bool thumb16); | ||
418 | |||
419 | |||
420 | #endif /* _ARM_KERNEL_KPROBES_H */ | ||
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c index 262ea67f60ae..31326996dfeb 100644 --- a/arch/arm/kernel/perf_event.c +++ b/arch/arm/kernel/perf_event.c | |||
@@ -583,7 +583,7 @@ static int armpmu_event_init(struct perf_event *event) | |||
583 | static void armpmu_enable(struct pmu *pmu) | 583 | static void armpmu_enable(struct pmu *pmu) |
584 | { | 584 | { |
585 | /* Enable all of the perf events on hardware. */ | 585 | /* Enable all of the perf events on hardware. */ |
586 | int idx; | 586 | int idx, enabled = 0; |
587 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); | 587 | struct cpu_hw_events *cpuc = &__get_cpu_var(cpu_hw_events); |
588 | 588 | ||
589 | if (!armpmu) | 589 | if (!armpmu) |
@@ -596,9 +596,11 @@ static void armpmu_enable(struct pmu *pmu) | |||
596 | continue; | 596 | continue; |
597 | 597 | ||
598 | armpmu->enable(&event->hw, idx); | 598 | armpmu->enable(&event->hw, idx); |
599 | enabled = 1; | ||
599 | } | 600 | } |
600 | 601 | ||
601 | armpmu->start(); | 602 | if (enabled) |
603 | armpmu->start(); | ||
602 | } | 604 | } |
603 | 605 | ||
604 | static void armpmu_disable(struct pmu *pmu) | 606 | static void armpmu_disable(struct pmu *pmu) |
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c index 97260060bf26..897ade059f58 100644 --- a/arch/arm/kernel/ptrace.c +++ b/arch/arm/kernel/ptrace.c | |||
@@ -228,34 +228,12 @@ static struct undef_hook thumb_break_hook = { | |||
228 | .fn = break_trap, | 228 | .fn = break_trap, |
229 | }; | 229 | }; |
230 | 230 | ||
231 | static int thumb2_break_trap(struct pt_regs *regs, unsigned int instr) | ||
232 | { | ||
233 | unsigned int instr2; | ||
234 | void __user *pc; | ||
235 | |||
236 | /* Check the second half of the instruction. */ | ||
237 | pc = (void __user *)(instruction_pointer(regs) + 2); | ||
238 | |||
239 | if (processor_mode(regs) == SVC_MODE) { | ||
240 | instr2 = *(u16 *) pc; | ||
241 | } else { | ||
242 | get_user(instr2, (u16 __user *)pc); | ||
243 | } | ||
244 | |||
245 | if (instr2 == 0xa000) { | ||
246 | ptrace_break(current, regs); | ||
247 | return 0; | ||
248 | } else { | ||
249 | return 1; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | static struct undef_hook thumb2_break_hook = { | 231 | static struct undef_hook thumb2_break_hook = { |
254 | .instr_mask = 0xffff, | 232 | .instr_mask = 0xffffffff, |
255 | .instr_val = 0xf7f0, | 233 | .instr_val = 0xf7f0a000, |
256 | .cpsr_mask = PSR_T_BIT, | 234 | .cpsr_mask = PSR_T_BIT, |
257 | .cpsr_val = PSR_T_BIT, | 235 | .cpsr_val = PSR_T_BIT, |
258 | .fn = thumb2_break_trap, | 236 | .fn = break_trap, |
259 | }; | 237 | }; |
260 | 238 | ||
261 | static int __init ptrace_break_init(void) | 239 | static int __init ptrace_break_init(void) |
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c index 699df68fc840..7cc11c07adda 100644 --- a/arch/arm/kernel/setup.c +++ b/arch/arm/kernel/setup.c | |||
@@ -73,6 +73,7 @@ __setup("fpe=", fpe_setup); | |||
73 | #endif | 73 | #endif |
74 | 74 | ||
75 | extern void paging_init(struct machine_desc *desc); | 75 | extern void paging_init(struct machine_desc *desc); |
76 | extern void sanity_check_meminfo(void); | ||
76 | extern void reboot_setup(char *str); | 77 | extern void reboot_setup(char *str); |
77 | 78 | ||
78 | unsigned int processor_id; | 79 | unsigned int processor_id; |
@@ -900,6 +901,7 @@ void __init setup_arch(char **cmdline_p) | |||
900 | 901 | ||
901 | parse_early_param(); | 902 | parse_early_param(); |
902 | 903 | ||
904 | sanity_check_meminfo(); | ||
903 | arm_memblock_init(&meminfo, mdesc); | 905 | arm_memblock_init(&meminfo, mdesc); |
904 | 906 | ||
905 | paging_init(mdesc); | 907 | paging_init(mdesc); |
diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index 60636f499cb3..2c277d40cee6 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c | |||
@@ -115,7 +115,7 @@ static void __cpuinit twd_calibrate_rate(void) | |||
115 | twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); | 115 | twd_timer_rate = (0xFFFFFFFFU - count) * (HZ / 5); |
116 | 116 | ||
117 | printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000, | 117 | printk("%lu.%02luMHz.\n", twd_timer_rate / 1000000, |
118 | (twd_timer_rate / 1000000) % 100); | 118 | (twd_timer_rate / 10000) % 100); |
119 | } | 119 | } |
120 | } | 120 | } |
121 | 121 | ||
diff --git a/arch/arm/kernel/traps.c b/arch/arm/kernel/traps.c index 6807cb1e76dd..2d3436e9f71f 100644 --- a/arch/arm/kernel/traps.c +++ b/arch/arm/kernel/traps.c | |||
@@ -355,9 +355,24 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs) | |||
355 | pc = (void __user *)instruction_pointer(regs); | 355 | pc = (void __user *)instruction_pointer(regs); |
356 | 356 | ||
357 | if (processor_mode(regs) == SVC_MODE) { | 357 | if (processor_mode(regs) == SVC_MODE) { |
358 | instr = *(u32 *) pc; | 358 | #ifdef CONFIG_THUMB2_KERNEL |
359 | if (thumb_mode(regs)) { | ||
360 | instr = ((u16 *)pc)[0]; | ||
361 | if (is_wide_instruction(instr)) { | ||
362 | instr <<= 16; | ||
363 | instr |= ((u16 *)pc)[1]; | ||
364 | } | ||
365 | } else | ||
366 | #endif | ||
367 | instr = *(u32 *) pc; | ||
359 | } else if (thumb_mode(regs)) { | 368 | } else if (thumb_mode(regs)) { |
360 | get_user(instr, (u16 __user *)pc); | 369 | get_user(instr, (u16 __user *)pc); |
370 | if (is_wide_instruction(instr)) { | ||
371 | unsigned int instr2; | ||
372 | get_user(instr2, (u16 __user *)pc+1); | ||
373 | instr <<= 16; | ||
374 | instr |= instr2; | ||
375 | } | ||
361 | } else { | 376 | } else { |
362 | get_user(instr, (u32 __user *)pc); | 377 | get_user(instr, (u32 __user *)pc); |
363 | } | 378 | } |
diff --git a/arch/arm/mach-at91/at91cap9.c b/arch/arm/mach-at91/at91cap9.c index 17fae4a42ab5..f1013d08bb57 100644 --- a/arch/arm/mach-at91/at91cap9.c +++ b/arch/arm/mach-at91/at91cap9.c | |||
@@ -223,15 +223,15 @@ static struct clk *periph_clocks[] __initdata = { | |||
223 | }; | 223 | }; |
224 | 224 | ||
225 | static struct clk_lookup periph_clocks_lookups[] = { | 225 | static struct clk_lookup periph_clocks_lookups[] = { |
226 | CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk), | 226 | CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk), |
227 | CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk), | 227 | CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk), |
228 | CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk), | 228 | CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk), |
229 | CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk), | 229 | CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk), |
230 | CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), | 230 | CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), |
231 | CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), | 231 | CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), |
232 | CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk), | 232 | CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk), |
233 | CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk), | 233 | CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), |
234 | CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk), | 234 | CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), |
235 | }; | 235 | }; |
236 | 236 | ||
237 | static struct clk_lookup usart_clocks_lookups[] = { | 237 | static struct clk_lookup usart_clocks_lookups[] = { |
diff --git a/arch/arm/mach-at91/at91cap9_devices.c b/arch/arm/mach-at91/at91cap9_devices.c index cd850ed6f335..dba0d8d8a4bd 100644 --- a/arch/arm/mach-at91/at91cap9_devices.c +++ b/arch/arm/mach-at91/at91cap9_devices.c | |||
@@ -1220,7 +1220,7 @@ void __init at91_set_serial_console(unsigned portnr) | |||
1220 | { | 1220 | { |
1221 | if (portnr < ATMEL_MAX_UART) { | 1221 | if (portnr < ATMEL_MAX_UART) { |
1222 | atmel_default_console_device = at91_uarts[portnr]; | 1222 | atmel_default_console_device = at91_uarts[portnr]; |
1223 | at91cap9_set_console_clock(portnr); | 1223 | at91cap9_set_console_clock(at91_uarts[portnr]->id); |
1224 | } | 1224 | } |
1225 | } | 1225 | } |
1226 | 1226 | ||
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c index b228ce9e21a1..83a1a3fee554 100644 --- a/arch/arm/mach-at91/at91rm9200.c +++ b/arch/arm/mach-at91/at91rm9200.c | |||
@@ -199,9 +199,9 @@ static struct clk_lookup periph_clocks_lookups[] = { | |||
199 | CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk), | 199 | CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk), |
200 | CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk), | 200 | CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk), |
201 | CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk), | 201 | CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk), |
202 | CLKDEV_CON_DEV_ID("ssc", "ssc.0", &ssc0_clk), | 202 | CLKDEV_CON_DEV_ID("pclk", "ssc.0", &ssc0_clk), |
203 | CLKDEV_CON_DEV_ID("ssc", "ssc.1", &ssc1_clk), | 203 | CLKDEV_CON_DEV_ID("pclk", "ssc.1", &ssc1_clk), |
204 | CLKDEV_CON_DEV_ID("ssc", "ssc.2", &ssc2_clk), | 204 | CLKDEV_CON_DEV_ID("pclk", "ssc.2", &ssc2_clk), |
205 | }; | 205 | }; |
206 | 206 | ||
207 | static struct clk_lookup usart_clocks_lookups[] = { | 207 | static struct clk_lookup usart_clocks_lookups[] = { |
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c index a0ba475be04c..7227755ffec6 100644 --- a/arch/arm/mach-at91/at91rm9200_devices.c +++ b/arch/arm/mach-at91/at91rm9200_devices.c | |||
@@ -1135,7 +1135,7 @@ void __init at91_set_serial_console(unsigned portnr) | |||
1135 | { | 1135 | { |
1136 | if (portnr < ATMEL_MAX_UART) { | 1136 | if (portnr < ATMEL_MAX_UART) { |
1137 | atmel_default_console_device = at91_uarts[portnr]; | 1137 | atmel_default_console_device = at91_uarts[portnr]; |
1138 | at91rm9200_set_console_clock(portnr); | 1138 | at91rm9200_set_console_clock(at91_uarts[portnr]->id); |
1139 | } | 1139 | } |
1140 | } | 1140 | } |
1141 | 1141 | ||
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c index 1fdeb9058a76..39f81f47b4ba 100644 --- a/arch/arm/mach-at91/at91sam9260_devices.c +++ b/arch/arm/mach-at91/at91sam9260_devices.c | |||
@@ -1173,7 +1173,7 @@ void __init at91_set_serial_console(unsigned portnr) | |||
1173 | { | 1173 | { |
1174 | if (portnr < ATMEL_MAX_UART) { | 1174 | if (portnr < ATMEL_MAX_UART) { |
1175 | atmel_default_console_device = at91_uarts[portnr]; | 1175 | atmel_default_console_device = at91_uarts[portnr]; |
1176 | at91sam9260_set_console_clock(portnr); | 1176 | at91sam9260_set_console_clock(at91_uarts[portnr]->id); |
1177 | } | 1177 | } |
1178 | } | 1178 | } |
1179 | 1179 | ||
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c index 3eb4538fceeb..5004bf0a05f2 100644 --- a/arch/arm/mach-at91/at91sam9261_devices.c +++ b/arch/arm/mach-at91/at91sam9261_devices.c | |||
@@ -1013,7 +1013,7 @@ void __init at91_set_serial_console(unsigned portnr) | |||
1013 | { | 1013 | { |
1014 | if (portnr < ATMEL_MAX_UART) { | 1014 | if (portnr < ATMEL_MAX_UART) { |
1015 | atmel_default_console_device = at91_uarts[portnr]; | 1015 | atmel_default_console_device = at91_uarts[portnr]; |
1016 | at91sam9261_set_console_clock(portnr); | 1016 | at91sam9261_set_console_clock(at91_uarts[portnr]->id); |
1017 | } | 1017 | } |
1018 | } | 1018 | } |
1019 | 1019 | ||
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c index ffe081b77ed0..a050f41fc860 100644 --- a/arch/arm/mach-at91/at91sam9263_devices.c +++ b/arch/arm/mach-at91/at91sam9263_devices.c | |||
@@ -1395,7 +1395,7 @@ void __init at91_set_serial_console(unsigned portnr) | |||
1395 | { | 1395 | { |
1396 | if (portnr < ATMEL_MAX_UART) { | 1396 | if (portnr < ATMEL_MAX_UART) { |
1397 | atmel_default_console_device = at91_uarts[portnr]; | 1397 | atmel_default_console_device = at91_uarts[portnr]; |
1398 | at91sam9263_set_console_clock(portnr); | 1398 | at91sam9263_set_console_clock(at91_uarts[portnr]->id); |
1399 | } | 1399 | } |
1400 | } | 1400 | } |
1401 | 1401 | ||
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c index 2bb6ff9af1c7..11e214121b23 100644 --- a/arch/arm/mach-at91/at91sam9g45.c +++ b/arch/arm/mach-at91/at91sam9g45.c | |||
@@ -217,11 +217,11 @@ static struct clk *periph_clocks[] __initdata = { | |||
217 | static struct clk_lookup periph_clocks_lookups[] = { | 217 | static struct clk_lookup periph_clocks_lookups[] = { |
218 | /* One additional fake clock for ohci */ | 218 | /* One additional fake clock for ohci */ |
219 | CLKDEV_CON_ID("ohci_clk", &uhphs_clk), | 219 | CLKDEV_CON_ID("ohci_clk", &uhphs_clk), |
220 | CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci.0", &uhphs_clk), | 220 | CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci", &uhphs_clk), |
221 | CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk), | 221 | CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk), |
222 | CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk), | 222 | CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk), |
223 | CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.0", &mmc0_clk), | 223 | CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk), |
224 | CLKDEV_CON_DEV_ID("mci_clk", "at91_mci.1", &mmc1_clk), | 224 | CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk), |
225 | CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), | 225 | CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk), |
226 | CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), | 226 | CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk), |
227 | CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk), | 227 | CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk), |
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c index 05674865bc21..600bffb01edb 100644 --- a/arch/arm/mach-at91/at91sam9g45_devices.c +++ b/arch/arm/mach-at91/at91sam9g45_devices.c | |||
@@ -1550,7 +1550,7 @@ void __init at91_set_serial_console(unsigned portnr) | |||
1550 | { | 1550 | { |
1551 | if (portnr < ATMEL_MAX_UART) { | 1551 | if (portnr < ATMEL_MAX_UART) { |
1552 | atmel_default_console_device = at91_uarts[portnr]; | 1552 | atmel_default_console_device = at91_uarts[portnr]; |
1553 | at91sam9g45_set_console_clock(portnr); | 1553 | at91sam9g45_set_console_clock(at91_uarts[portnr]->id); |
1554 | } | 1554 | } |
1555 | } | 1555 | } |
1556 | 1556 | ||
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c index 1a40f16b66c8..29dff18ed130 100644 --- a/arch/arm/mach-at91/at91sam9rl.c +++ b/arch/arm/mach-at91/at91sam9rl.c | |||
@@ -191,8 +191,8 @@ static struct clk *periph_clocks[] __initdata = { | |||
191 | }; | 191 | }; |
192 | 192 | ||
193 | static struct clk_lookup periph_clocks_lookups[] = { | 193 | static struct clk_lookup periph_clocks_lookups[] = { |
194 | CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc.0", &utmi_clk), | 194 | CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk), |
195 | CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc.0", &udphs_clk), | 195 | CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk), |
196 | CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk), | 196 | CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk), |
197 | CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk), | 197 | CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk), |
198 | CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk), | 198 | CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk), |
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c index c296045f2b6a..aacb19dc9225 100644 --- a/arch/arm/mach-at91/at91sam9rl_devices.c +++ b/arch/arm/mach-at91/at91sam9rl_devices.c | |||
@@ -1168,7 +1168,7 @@ void __init at91_set_serial_console(unsigned portnr) | |||
1168 | { | 1168 | { |
1169 | if (portnr < ATMEL_MAX_UART) { | 1169 | if (portnr < ATMEL_MAX_UART) { |
1170 | atmel_default_console_device = at91_uarts[portnr]; | 1170 | atmel_default_console_device = at91_uarts[portnr]; |
1171 | at91sam9rl_set_console_clock(portnr); | 1171 | at91sam9rl_set_console_clock(at91_uarts[portnr]->id); |
1172 | } | 1172 | } |
1173 | } | 1173 | } |
1174 | 1174 | ||
diff --git a/arch/arm/mach-at91/board-cap9adk.c b/arch/arm/mach-at91/board-cap9adk.c index 1904fdf87613..cdb65d483250 100644 --- a/arch/arm/mach-at91/board-cap9adk.c +++ b/arch/arm/mach-at91/board-cap9adk.c | |||
@@ -215,7 +215,7 @@ static void __init cap9adk_add_device_nand(void) | |||
215 | csa = at91_sys_read(AT91_MATRIX_EBICSA); | 215 | csa = at91_sys_read(AT91_MATRIX_EBICSA); |
216 | at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V); | 216 | at91_sys_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_VDDIOMSEL_3_3V); |
217 | 217 | ||
218 | cap9adk_nand_data.bus_width_16 = !board_have_nand_8bit(); | 218 | cap9adk_nand_data.bus_width_16 = board_have_nand_16bit(); |
219 | /* setup bus-width (8 or 16) */ | 219 | /* setup bus-width (8 or 16) */ |
220 | if (cap9adk_nand_data.bus_width_16) | 220 | if (cap9adk_nand_data.bus_width_16) |
221 | cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_16; | 221 | cap9adk_nand_smc_config.mode |= AT91_SMC_DBW_16; |
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c index d600dc123227..5c240743c5b7 100644 --- a/arch/arm/mach-at91/board-sam9260ek.c +++ b/arch/arm/mach-at91/board-sam9260ek.c | |||
@@ -214,7 +214,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = { | |||
214 | 214 | ||
215 | static void __init ek_add_device_nand(void) | 215 | static void __init ek_add_device_nand(void) |
216 | { | 216 | { |
217 | ek_nand_data.bus_width_16 = !board_have_nand_8bit(); | 217 | ek_nand_data.bus_width_16 = board_have_nand_16bit(); |
218 | /* setup bus-width (8 or 16) */ | 218 | /* setup bus-width (8 or 16) */ |
219 | if (ek_nand_data.bus_width_16) | 219 | if (ek_nand_data.bus_width_16) |
220 | ek_nand_smc_config.mode |= AT91_SMC_DBW_16; | 220 | ek_nand_smc_config.mode |= AT91_SMC_DBW_16; |
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c index f897f84d43dc..b60c22b6e241 100644 --- a/arch/arm/mach-at91/board-sam9261ek.c +++ b/arch/arm/mach-at91/board-sam9261ek.c | |||
@@ -220,7 +220,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = { | |||
220 | 220 | ||
221 | static void __init ek_add_device_nand(void) | 221 | static void __init ek_add_device_nand(void) |
222 | { | 222 | { |
223 | ek_nand_data.bus_width_16 = !board_have_nand_8bit(); | 223 | ek_nand_data.bus_width_16 = board_have_nand_16bit(); |
224 | /* setup bus-width (8 or 16) */ | 224 | /* setup bus-width (8 or 16) */ |
225 | if (ek_nand_data.bus_width_16) | 225 | if (ek_nand_data.bus_width_16) |
226 | ek_nand_smc_config.mode |= AT91_SMC_DBW_16; | 226 | ek_nand_smc_config.mode |= AT91_SMC_DBW_16; |
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c index 605b26f40a4c..9bbdc92ea194 100644 --- a/arch/arm/mach-at91/board-sam9263ek.c +++ b/arch/arm/mach-at91/board-sam9263ek.c | |||
@@ -221,7 +221,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = { | |||
221 | 221 | ||
222 | static void __init ek_add_device_nand(void) | 222 | static void __init ek_add_device_nand(void) |
223 | { | 223 | { |
224 | ek_nand_data.bus_width_16 = !board_have_nand_8bit(); | 224 | ek_nand_data.bus_width_16 = board_have_nand_16bit(); |
225 | /* setup bus-width (8 or 16) */ | 225 | /* setup bus-width (8 or 16) */ |
226 | if (ek_nand_data.bus_width_16) | 226 | if (ek_nand_data.bus_width_16) |
227 | ek_nand_smc_config.mode |= AT91_SMC_DBW_16; | 227 | ek_nand_smc_config.mode |= AT91_SMC_DBW_16; |
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c index 7624cf0d006b..1325a50101a8 100644 --- a/arch/arm/mach-at91/board-sam9g20ek.c +++ b/arch/arm/mach-at91/board-sam9g20ek.c | |||
@@ -198,7 +198,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = { | |||
198 | 198 | ||
199 | static void __init ek_add_device_nand(void) | 199 | static void __init ek_add_device_nand(void) |
200 | { | 200 | { |
201 | ek_nand_data.bus_width_16 = !board_have_nand_8bit(); | 201 | ek_nand_data.bus_width_16 = board_have_nand_16bit(); |
202 | /* setup bus-width (8 or 16) */ | 202 | /* setup bus-width (8 or 16) */ |
203 | if (ek_nand_data.bus_width_16) | 203 | if (ek_nand_data.bus_width_16) |
204 | ek_nand_smc_config.mode |= AT91_SMC_DBW_16; | 204 | ek_nand_smc_config.mode |= AT91_SMC_DBW_16; |
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c index 063c95d0e8f0..33eaa135f248 100644 --- a/arch/arm/mach-at91/board-sam9m10g45ek.c +++ b/arch/arm/mach-at91/board-sam9m10g45ek.c | |||
@@ -178,7 +178,7 @@ static struct sam9_smc_config __initdata ek_nand_smc_config = { | |||
178 | 178 | ||
179 | static void __init ek_add_device_nand(void) | 179 | static void __init ek_add_device_nand(void) |
180 | { | 180 | { |
181 | ek_nand_data.bus_width_16 = !board_have_nand_8bit(); | 181 | ek_nand_data.bus_width_16 = board_have_nand_16bit(); |
182 | /* setup bus-width (8 or 16) */ | 182 | /* setup bus-width (8 or 16) */ |
183 | if (ek_nand_data.bus_width_16) | 183 | if (ek_nand_data.bus_width_16) |
184 | ek_nand_smc_config.mode |= AT91_SMC_DBW_16; | 184 | ek_nand_smc_config.mode |= AT91_SMC_DBW_16; |
diff --git a/arch/arm/mach-at91/include/mach/system_rev.h b/arch/arm/mach-at91/include/mach/system_rev.h index b855ee75f72c..8f4866045b41 100644 --- a/arch/arm/mach-at91/include/mach/system_rev.h +++ b/arch/arm/mach-at91/include/mach/system_rev.h | |||
@@ -13,13 +13,13 @@ | |||
13 | * the 16-31 bit are reserved for at91 generic information | 13 | * the 16-31 bit are reserved for at91 generic information |
14 | * | 14 | * |
15 | * bit 31: | 15 | * bit 31: |
16 | * 0 => nand 16 bit | 16 | * 0 => nand 8 bit |
17 | * 1 => nand 8 bit | 17 | * 1 => nand 16 bit |
18 | */ | 18 | */ |
19 | #define BOARD_HAVE_NAND_8BIT (1 << 31) | 19 | #define BOARD_HAVE_NAND_16BIT (1 << 31) |
20 | static int inline board_have_nand_8bit(void) | 20 | static inline int board_have_nand_16bit(void) |
21 | { | 21 | { |
22 | return system_rev & BOARD_HAVE_NAND_8BIT; | 22 | return system_rev & BOARD_HAVE_NAND_16BIT; |
23 | } | 23 | } |
24 | 24 | ||
25 | #endif /* __ARCH_SYSTEM_REV_H__ */ | 25 | #endif /* __ARCH_SYSTEM_REV_H__ */ |
diff --git a/arch/arm/mach-ep93xx/core.c b/arch/arm/mach-ep93xx/core.c index 1d4b65fd673e..6659a0d137a3 100644 --- a/arch/arm/mach-ep93xx/core.c +++ b/arch/arm/mach-ep93xx/core.c | |||
@@ -251,9 +251,9 @@ static void ep93xx_uart_set_mctrl(struct amba_device *dev, | |||
251 | unsigned int mcr; | 251 | unsigned int mcr; |
252 | 252 | ||
253 | mcr = 0; | 253 | mcr = 0; |
254 | if (!(mctrl & TIOCM_RTS)) | 254 | if (mctrl & TIOCM_RTS) |
255 | mcr |= 2; | 255 | mcr |= 2; |
256 | if (!(mctrl & TIOCM_DTR)) | 256 | if (mctrl & TIOCM_DTR) |
257 | mcr |= 1; | 257 | mcr |= 1; |
258 | 258 | ||
259 | __raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET); | 259 | __raw_writel(mcr, base + EP93XX_UART_MCR_OFFSET); |
diff --git a/arch/arm/mach-exynos4/cpu.c b/arch/arm/mach-exynos4/cpu.c index 9babe4473e88..bfd621460abf 100644 --- a/arch/arm/mach-exynos4/cpu.c +++ b/arch/arm/mach-exynos4/cpu.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <plat/sdhci.h> | 23 | #include <plat/sdhci.h> |
24 | #include <plat/devs.h> | 24 | #include <plat/devs.h> |
25 | #include <plat/fimc-core.h> | 25 | #include <plat/fimc-core.h> |
26 | #include <plat/iic-core.h> | ||
26 | 27 | ||
27 | #include <mach/regs-irq.h> | 28 | #include <mach/regs-irq.h> |
28 | 29 | ||
@@ -132,6 +133,11 @@ void __init exynos4_map_io(void) | |||
132 | s3c_fimc_setname(1, "exynos4-fimc"); | 133 | s3c_fimc_setname(1, "exynos4-fimc"); |
133 | s3c_fimc_setname(2, "exynos4-fimc"); | 134 | s3c_fimc_setname(2, "exynos4-fimc"); |
134 | s3c_fimc_setname(3, "exynos4-fimc"); | 135 | s3c_fimc_setname(3, "exynos4-fimc"); |
136 | |||
137 | /* The I2C bus controllers are directly compatible with s3c2440 */ | ||
138 | s3c_i2c0_setname("s3c2440-i2c"); | ||
139 | s3c_i2c1_setname("s3c2440-i2c"); | ||
140 | s3c_i2c2_setname("s3c2440-i2c"); | ||
135 | } | 141 | } |
136 | 142 | ||
137 | void __init exynos4_init_clocks(int xtal) | 143 | void __init exynos4_init_clocks(int xtal) |
diff --git a/arch/arm/mach-exynos4/dev-audio.c b/arch/arm/mach-exynos4/dev-audio.c index 1eed5f9f7bd3..983069a53239 100644 --- a/arch/arm/mach-exynos4/dev-audio.c +++ b/arch/arm/mach-exynos4/dev-audio.c | |||
@@ -330,7 +330,7 @@ struct platform_device exynos4_device_ac97 = { | |||
330 | 330 | ||
331 | static int exynos4_spdif_cfg_gpio(struct platform_device *pdev) | 331 | static int exynos4_spdif_cfg_gpio(struct platform_device *pdev) |
332 | { | 332 | { |
333 | s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(3)); | 333 | s3c_gpio_cfgpin_range(EXYNOS4_GPC1(0), 2, S3C_GPIO_SFN(4)); |
334 | 334 | ||
335 | return 0; | 335 | return 0; |
336 | } | 336 | } |
diff --git a/arch/arm/mach-exynos4/headsmp.S b/arch/arm/mach-exynos4/headsmp.S index 6c6cfc50c46b..3cdeb3647542 100644 --- a/arch/arm/mach-exynos4/headsmp.S +++ b/arch/arm/mach-exynos4/headsmp.S | |||
@@ -13,7 +13,7 @@ | |||
13 | #include <linux/linkage.h> | 13 | #include <linux/linkage.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | 15 | ||
16 | __INIT | 16 | __CPUINIT |
17 | 17 | ||
18 | /* | 18 | /* |
19 | * exynos4 specific entry point for secondary CPUs. This provides | 19 | * exynos4 specific entry point for secondary CPUs. This provides |
diff --git a/arch/arm/mach-exynos4/init.c b/arch/arm/mach-exynos4/init.c index cf91f50e43ab..a8a83e3881a4 100644 --- a/arch/arm/mach-exynos4/init.c +++ b/arch/arm/mach-exynos4/init.c | |||
@@ -35,6 +35,7 @@ void __init exynos4_common_init_uarts(struct s3c2410_uartcfg *cfg, int no) | |||
35 | tcfg->clocks = exynos4_serial_clocks; | 35 | tcfg->clocks = exynos4_serial_clocks; |
36 | tcfg->clocks_size = ARRAY_SIZE(exynos4_serial_clocks); | 36 | tcfg->clocks_size = ARRAY_SIZE(exynos4_serial_clocks); |
37 | } | 37 | } |
38 | tcfg->flags |= NO_NEED_CHECK_CLKSRC; | ||
38 | } | 39 | } |
39 | 40 | ||
40 | s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no); | 41 | s3c24xx_init_uartdevs("s5pv210-uart", s5p_uart_resources, cfg, no); |
diff --git a/arch/arm/mach-exynos4/mach-smdkv310.c b/arch/arm/mach-exynos4/mach-smdkv310.c index 152676471b67..edd814110da8 100644 --- a/arch/arm/mach-exynos4/mach-smdkv310.c +++ b/arch/arm/mach-exynos4/mach-smdkv310.c | |||
@@ -78,9 +78,7 @@ static struct s3c2410_uartcfg smdkv310_uartcfgs[] __initdata = { | |||
78 | }; | 78 | }; |
79 | 79 | ||
80 | static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = { | 80 | static struct s3c_sdhci_platdata smdkv310_hsmmc0_pdata __initdata = { |
81 | .cd_type = S3C_SDHCI_CD_GPIO, | 81 | .cd_type = S3C_SDHCI_CD_INTERNAL, |
82 | .ext_cd_gpio = EXYNOS4_GPK0(2), | ||
83 | .ext_cd_gpio_invert = 1, | ||
84 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, | 82 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, |
85 | #ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT | 83 | #ifdef CONFIG_EXYNOS4_SDHCI_CH0_8BIT |
86 | .max_width = 8, | 84 | .max_width = 8, |
@@ -96,9 +94,7 @@ static struct s3c_sdhci_platdata smdkv310_hsmmc1_pdata __initdata = { | |||
96 | }; | 94 | }; |
97 | 95 | ||
98 | static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = { | 96 | static struct s3c_sdhci_platdata smdkv310_hsmmc2_pdata __initdata = { |
99 | .cd_type = S3C_SDHCI_CD_GPIO, | 97 | .cd_type = S3C_SDHCI_CD_INTERNAL, |
100 | .ext_cd_gpio = EXYNOS4_GPK2(2), | ||
101 | .ext_cd_gpio_invert = 1, | ||
102 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, | 98 | .clk_type = S3C_SDHCI_CLK_DIV_EXTERNAL, |
103 | #ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT | 99 | #ifdef CONFIG_EXYNOS4_SDHCI_CH2_8BIT |
104 | .max_width = 8, | 100 | .max_width = 8, |
diff --git a/arch/arm/mach-omap1/board-ams-delta.c b/arch/arm/mach-omap1/board-ams-delta.c index de88c9297b68..f49ce85d2448 100644 --- a/arch/arm/mach-omap1/board-ams-delta.c +++ b/arch/arm/mach-omap1/board-ams-delta.c | |||
@@ -215,7 +215,7 @@ static struct omap_kp_platform_data ams_delta_kp_data __initdata = { | |||
215 | .delay = 9, | 215 | .delay = 9, |
216 | }; | 216 | }; |
217 | 217 | ||
218 | static struct platform_device ams_delta_kp_device __initdata = { | 218 | static struct platform_device ams_delta_kp_device = { |
219 | .name = "omap-keypad", | 219 | .name = "omap-keypad", |
220 | .id = -1, | 220 | .id = -1, |
221 | .dev = { | 221 | .dev = { |
@@ -225,12 +225,12 @@ static struct platform_device ams_delta_kp_device __initdata = { | |||
225 | .resource = ams_delta_kp_resources, | 225 | .resource = ams_delta_kp_resources, |
226 | }; | 226 | }; |
227 | 227 | ||
228 | static struct platform_device ams_delta_lcd_device __initdata = { | 228 | static struct platform_device ams_delta_lcd_device = { |
229 | .name = "lcd_ams_delta", | 229 | .name = "lcd_ams_delta", |
230 | .id = -1, | 230 | .id = -1, |
231 | }; | 231 | }; |
232 | 232 | ||
233 | static struct platform_device ams_delta_led_device __initdata = { | 233 | static struct platform_device ams_delta_led_device = { |
234 | .name = "ams-delta-led", | 234 | .name = "ams-delta-led", |
235 | .id = -1 | 235 | .id = -1 |
236 | }; | 236 | }; |
@@ -267,7 +267,7 @@ static struct soc_camera_link ams_delta_iclink = { | |||
267 | .power = ams_delta_camera_power, | 267 | .power = ams_delta_camera_power, |
268 | }; | 268 | }; |
269 | 269 | ||
270 | static struct platform_device ams_delta_camera_device __initdata = { | 270 | static struct platform_device ams_delta_camera_device = { |
271 | .name = "soc-camera-pdrv", | 271 | .name = "soc-camera-pdrv", |
272 | .id = 0, | 272 | .id = 0, |
273 | .dev = { | 273 | .dev = { |
diff --git a/arch/arm/mach-omap1/gpio15xx.c b/arch/arm/mach-omap1/gpio15xx.c index 04c4b04cf54e..364137c2042c 100644 --- a/arch/arm/mach-omap1/gpio15xx.c +++ b/arch/arm/mach-omap1/gpio15xx.c | |||
@@ -41,7 +41,7 @@ static struct __initdata omap_gpio_platform_data omap15xx_mpu_gpio_config = { | |||
41 | .bank_stride = 1, | 41 | .bank_stride = 1, |
42 | }; | 42 | }; |
43 | 43 | ||
44 | static struct __initdata platform_device omap15xx_mpu_gpio = { | 44 | static struct platform_device omap15xx_mpu_gpio = { |
45 | .name = "omap_gpio", | 45 | .name = "omap_gpio", |
46 | .id = 0, | 46 | .id = 0, |
47 | .dev = { | 47 | .dev = { |
@@ -70,7 +70,7 @@ static struct __initdata omap_gpio_platform_data omap15xx_gpio_config = { | |||
70 | .bank_width = 16, | 70 | .bank_width = 16, |
71 | }; | 71 | }; |
72 | 72 | ||
73 | static struct __initdata platform_device omap15xx_gpio = { | 73 | static struct platform_device omap15xx_gpio = { |
74 | .name = "omap_gpio", | 74 | .name = "omap_gpio", |
75 | .id = 1, | 75 | .id = 1, |
76 | .dev = { | 76 | .dev = { |
diff --git a/arch/arm/mach-omap1/gpio16xx.c b/arch/arm/mach-omap1/gpio16xx.c index 5dd0d4c82b24..293a246e2824 100644 --- a/arch/arm/mach-omap1/gpio16xx.c +++ b/arch/arm/mach-omap1/gpio16xx.c | |||
@@ -44,7 +44,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_mpu_gpio_config = { | |||
44 | .bank_stride = 1, | 44 | .bank_stride = 1, |
45 | }; | 45 | }; |
46 | 46 | ||
47 | static struct __initdata platform_device omap16xx_mpu_gpio = { | 47 | static struct platform_device omap16xx_mpu_gpio = { |
48 | .name = "omap_gpio", | 48 | .name = "omap_gpio", |
49 | .id = 0, | 49 | .id = 0, |
50 | .dev = { | 50 | .dev = { |
@@ -73,7 +73,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio1_config = { | |||
73 | .bank_width = 16, | 73 | .bank_width = 16, |
74 | }; | 74 | }; |
75 | 75 | ||
76 | static struct __initdata platform_device omap16xx_gpio1 = { | 76 | static struct platform_device omap16xx_gpio1 = { |
77 | .name = "omap_gpio", | 77 | .name = "omap_gpio", |
78 | .id = 1, | 78 | .id = 1, |
79 | .dev = { | 79 | .dev = { |
@@ -102,7 +102,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio2_config = { | |||
102 | .bank_width = 16, | 102 | .bank_width = 16, |
103 | }; | 103 | }; |
104 | 104 | ||
105 | static struct __initdata platform_device omap16xx_gpio2 = { | 105 | static struct platform_device omap16xx_gpio2 = { |
106 | .name = "omap_gpio", | 106 | .name = "omap_gpio", |
107 | .id = 2, | 107 | .id = 2, |
108 | .dev = { | 108 | .dev = { |
@@ -131,7 +131,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio3_config = { | |||
131 | .bank_width = 16, | 131 | .bank_width = 16, |
132 | }; | 132 | }; |
133 | 133 | ||
134 | static struct __initdata platform_device omap16xx_gpio3 = { | 134 | static struct platform_device omap16xx_gpio3 = { |
135 | .name = "omap_gpio", | 135 | .name = "omap_gpio", |
136 | .id = 3, | 136 | .id = 3, |
137 | .dev = { | 137 | .dev = { |
@@ -160,7 +160,7 @@ static struct __initdata omap_gpio_platform_data omap16xx_gpio4_config = { | |||
160 | .bank_width = 16, | 160 | .bank_width = 16, |
161 | }; | 161 | }; |
162 | 162 | ||
163 | static struct __initdata platform_device omap16xx_gpio4 = { | 163 | static struct platform_device omap16xx_gpio4 = { |
164 | .name = "omap_gpio", | 164 | .name = "omap_gpio", |
165 | .id = 4, | 165 | .id = 4, |
166 | .dev = { | 166 | .dev = { |
diff --git a/arch/arm/mach-omap1/gpio7xx.c b/arch/arm/mach-omap1/gpio7xx.c index 1204c8b871af..c6ad248d63a6 100644 --- a/arch/arm/mach-omap1/gpio7xx.c +++ b/arch/arm/mach-omap1/gpio7xx.c | |||
@@ -46,7 +46,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_mpu_gpio_config = { | |||
46 | .bank_stride = 2, | 46 | .bank_stride = 2, |
47 | }; | 47 | }; |
48 | 48 | ||
49 | static struct __initdata platform_device omap7xx_mpu_gpio = { | 49 | static struct platform_device omap7xx_mpu_gpio = { |
50 | .name = "omap_gpio", | 50 | .name = "omap_gpio", |
51 | .id = 0, | 51 | .id = 0, |
52 | .dev = { | 52 | .dev = { |
@@ -75,7 +75,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio1_config = { | |||
75 | .bank_width = 32, | 75 | .bank_width = 32, |
76 | }; | 76 | }; |
77 | 77 | ||
78 | static struct __initdata platform_device omap7xx_gpio1 = { | 78 | static struct platform_device omap7xx_gpio1 = { |
79 | .name = "omap_gpio", | 79 | .name = "omap_gpio", |
80 | .id = 1, | 80 | .id = 1, |
81 | .dev = { | 81 | .dev = { |
@@ -104,7 +104,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio2_config = { | |||
104 | .bank_width = 32, | 104 | .bank_width = 32, |
105 | }; | 105 | }; |
106 | 106 | ||
107 | static struct __initdata platform_device omap7xx_gpio2 = { | 107 | static struct platform_device omap7xx_gpio2 = { |
108 | .name = "omap_gpio", | 108 | .name = "omap_gpio", |
109 | .id = 2, | 109 | .id = 2, |
110 | .dev = { | 110 | .dev = { |
@@ -133,7 +133,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio3_config = { | |||
133 | .bank_width = 32, | 133 | .bank_width = 32, |
134 | }; | 134 | }; |
135 | 135 | ||
136 | static struct __initdata platform_device omap7xx_gpio3 = { | 136 | static struct platform_device omap7xx_gpio3 = { |
137 | .name = "omap_gpio", | 137 | .name = "omap_gpio", |
138 | .id = 3, | 138 | .id = 3, |
139 | .dev = { | 139 | .dev = { |
@@ -162,7 +162,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio4_config = { | |||
162 | .bank_width = 32, | 162 | .bank_width = 32, |
163 | }; | 163 | }; |
164 | 164 | ||
165 | static struct __initdata platform_device omap7xx_gpio4 = { | 165 | static struct platform_device omap7xx_gpio4 = { |
166 | .name = "omap_gpio", | 166 | .name = "omap_gpio", |
167 | .id = 4, | 167 | .id = 4, |
168 | .dev = { | 168 | .dev = { |
@@ -191,7 +191,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio5_config = { | |||
191 | .bank_width = 32, | 191 | .bank_width = 32, |
192 | }; | 192 | }; |
193 | 193 | ||
194 | static struct __initdata platform_device omap7xx_gpio5 = { | 194 | static struct platform_device omap7xx_gpio5 = { |
195 | .name = "omap_gpio", | 195 | .name = "omap_gpio", |
196 | .id = 5, | 196 | .id = 5, |
197 | .dev = { | 197 | .dev = { |
@@ -220,7 +220,7 @@ static struct __initdata omap_gpio_platform_data omap7xx_gpio6_config = { | |||
220 | .bank_width = 32, | 220 | .bank_width = 32, |
221 | }; | 221 | }; |
222 | 222 | ||
223 | static struct __initdata platform_device omap7xx_gpio6 = { | 223 | static struct platform_device omap7xx_gpio6 = { |
224 | .name = "omap_gpio", | 224 | .name = "omap_gpio", |
225 | .id = 6, | 225 | .id = 6, |
226 | .dev = { | 226 | .dev = { |
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c index 990366726c58..88bd6f7705f0 100644 --- a/arch/arm/mach-omap2/board-rx51-peripherals.c +++ b/arch/arm/mach-omap2/board-rx51-peripherals.c | |||
@@ -558,7 +558,7 @@ static struct radio_si4713_platform_data rx51_si4713_data __initdata_or_module = | |||
558 | .subdev_board_info = &rx51_si4713_board_info, | 558 | .subdev_board_info = &rx51_si4713_board_info, |
559 | }; | 559 | }; |
560 | 560 | ||
561 | static struct platform_device rx51_si4713_dev __initdata_or_module = { | 561 | static struct platform_device rx51_si4713_dev = { |
562 | .name = "radio-si4713", | 562 | .name = "radio-si4713", |
563 | .id = -1, | 563 | .id = -1, |
564 | .dev = { | 564 | .dev = { |
diff --git a/arch/arm/mach-s3c2440/mach-mini2440.c b/arch/arm/mach-s3c2440/mach-mini2440.c index dd3120df09fe..fc2dc0b3d4fe 100644 --- a/arch/arm/mach-s3c2440/mach-mini2440.c +++ b/arch/arm/mach-s3c2440/mach-mini2440.c | |||
@@ -552,7 +552,7 @@ struct mini2440_features_t { | |||
552 | struct platform_device *optional[8]; | 552 | struct platform_device *optional[8]; |
553 | }; | 553 | }; |
554 | 554 | ||
555 | static void mini2440_parse_features( | 555 | static void __init mini2440_parse_features( |
556 | struct mini2440_features_t * features, | 556 | struct mini2440_features_t * features, |
557 | const char * features_str ) | 557 | const char * features_str ) |
558 | { | 558 | { |
diff --git a/arch/arm/mach-s3c64xx/dev-spi.c b/arch/arm/mach-s3c64xx/dev-spi.c index 82db072cb836..5e6b42089eb4 100644 --- a/arch/arm/mach-s3c64xx/dev-spi.c +++ b/arch/arm/mach-s3c64xx/dev-spi.c | |||
@@ -88,6 +88,7 @@ static struct s3c64xx_spi_info s3c64xx_spi0_pdata = { | |||
88 | .cfg_gpio = s3c64xx_spi_cfg_gpio, | 88 | .cfg_gpio = s3c64xx_spi_cfg_gpio, |
89 | .fifo_lvl_mask = 0x7f, | 89 | .fifo_lvl_mask = 0x7f, |
90 | .rx_lvl_offset = 13, | 90 | .rx_lvl_offset = 13, |
91 | .tx_st_done = 21, | ||
91 | }; | 92 | }; |
92 | 93 | ||
93 | static u64 spi_dmamask = DMA_BIT_MASK(32); | 94 | static u64 spi_dmamask = DMA_BIT_MASK(32); |
@@ -132,6 +133,7 @@ static struct s3c64xx_spi_info s3c64xx_spi1_pdata = { | |||
132 | .cfg_gpio = s3c64xx_spi_cfg_gpio, | 133 | .cfg_gpio = s3c64xx_spi_cfg_gpio, |
133 | .fifo_lvl_mask = 0x7f, | 134 | .fifo_lvl_mask = 0x7f, |
134 | .rx_lvl_offset = 13, | 135 | .rx_lvl_offset = 13, |
136 | .tx_st_done = 21, | ||
135 | }; | 137 | }; |
136 | 138 | ||
137 | struct platform_device s3c64xx_device_spi1 = { | 139 | struct platform_device s3c64xx_device_spi1 = { |
diff --git a/arch/arm/mach-s5p64x0/dev-spi.c b/arch/arm/mach-s5p64x0/dev-spi.c index e78ee18c76e3..ac825e826326 100644 --- a/arch/arm/mach-s5p64x0/dev-spi.c +++ b/arch/arm/mach-s5p64x0/dev-spi.c | |||
@@ -112,12 +112,14 @@ static struct s3c64xx_spi_info s5p6440_spi0_pdata = { | |||
112 | .cfg_gpio = s5p6440_spi_cfg_gpio, | 112 | .cfg_gpio = s5p6440_spi_cfg_gpio, |
113 | .fifo_lvl_mask = 0x1ff, | 113 | .fifo_lvl_mask = 0x1ff, |
114 | .rx_lvl_offset = 15, | 114 | .rx_lvl_offset = 15, |
115 | .tx_st_done = 25, | ||
115 | }; | 116 | }; |
116 | 117 | ||
117 | static struct s3c64xx_spi_info s5p6450_spi0_pdata = { | 118 | static struct s3c64xx_spi_info s5p6450_spi0_pdata = { |
118 | .cfg_gpio = s5p6450_spi_cfg_gpio, | 119 | .cfg_gpio = s5p6450_spi_cfg_gpio, |
119 | .fifo_lvl_mask = 0x1ff, | 120 | .fifo_lvl_mask = 0x1ff, |
120 | .rx_lvl_offset = 15, | 121 | .rx_lvl_offset = 15, |
122 | .tx_st_done = 25, | ||
121 | }; | 123 | }; |
122 | 124 | ||
123 | static u64 spi_dmamask = DMA_BIT_MASK(32); | 125 | static u64 spi_dmamask = DMA_BIT_MASK(32); |
@@ -160,12 +162,14 @@ static struct s3c64xx_spi_info s5p6440_spi1_pdata = { | |||
160 | .cfg_gpio = s5p6440_spi_cfg_gpio, | 162 | .cfg_gpio = s5p6440_spi_cfg_gpio, |
161 | .fifo_lvl_mask = 0x7f, | 163 | .fifo_lvl_mask = 0x7f, |
162 | .rx_lvl_offset = 15, | 164 | .rx_lvl_offset = 15, |
165 | .tx_st_done = 25, | ||
163 | }; | 166 | }; |
164 | 167 | ||
165 | static struct s3c64xx_spi_info s5p6450_spi1_pdata = { | 168 | static struct s3c64xx_spi_info s5p6450_spi1_pdata = { |
166 | .cfg_gpio = s5p6450_spi_cfg_gpio, | 169 | .cfg_gpio = s5p6450_spi_cfg_gpio, |
167 | .fifo_lvl_mask = 0x7f, | 170 | .fifo_lvl_mask = 0x7f, |
168 | .rx_lvl_offset = 15, | 171 | .rx_lvl_offset = 15, |
172 | .tx_st_done = 25, | ||
169 | }; | 173 | }; |
170 | 174 | ||
171 | struct platform_device s5p64x0_device_spi1 = { | 175 | struct platform_device s5p64x0_device_spi1 = { |
diff --git a/arch/arm/mach-s5pc100/dev-spi.c b/arch/arm/mach-s5pc100/dev-spi.c index 57b19794d9bb..e5d6c4dceb56 100644 --- a/arch/arm/mach-s5pc100/dev-spi.c +++ b/arch/arm/mach-s5pc100/dev-spi.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <mach/dma.h> | 15 | #include <mach/dma.h> |
16 | #include <mach/map.h> | 16 | #include <mach/map.h> |
17 | #include <mach/spi-clocks.h> | 17 | #include <mach/spi-clocks.h> |
18 | #include <mach/irqs.h> | ||
18 | 19 | ||
19 | #include <plat/s3c64xx-spi.h> | 20 | #include <plat/s3c64xx-spi.h> |
20 | #include <plat/gpio-cfg.h> | 21 | #include <plat/gpio-cfg.h> |
@@ -90,6 +91,7 @@ static struct s3c64xx_spi_info s5pc100_spi0_pdata = { | |||
90 | .fifo_lvl_mask = 0x7f, | 91 | .fifo_lvl_mask = 0x7f, |
91 | .rx_lvl_offset = 13, | 92 | .rx_lvl_offset = 13, |
92 | .high_speed = 1, | 93 | .high_speed = 1, |
94 | .tx_st_done = 21, | ||
93 | }; | 95 | }; |
94 | 96 | ||
95 | static u64 spi_dmamask = DMA_BIT_MASK(32); | 97 | static u64 spi_dmamask = DMA_BIT_MASK(32); |
@@ -134,6 +136,7 @@ static struct s3c64xx_spi_info s5pc100_spi1_pdata = { | |||
134 | .fifo_lvl_mask = 0x7f, | 136 | .fifo_lvl_mask = 0x7f, |
135 | .rx_lvl_offset = 13, | 137 | .rx_lvl_offset = 13, |
136 | .high_speed = 1, | 138 | .high_speed = 1, |
139 | .tx_st_done = 21, | ||
137 | }; | 140 | }; |
138 | 141 | ||
139 | struct platform_device s5pc100_device_spi1 = { | 142 | struct platform_device s5pc100_device_spi1 = { |
@@ -176,6 +179,7 @@ static struct s3c64xx_spi_info s5pc100_spi2_pdata = { | |||
176 | .fifo_lvl_mask = 0x7f, | 179 | .fifo_lvl_mask = 0x7f, |
177 | .rx_lvl_offset = 13, | 180 | .rx_lvl_offset = 13, |
178 | .high_speed = 1, | 181 | .high_speed = 1, |
182 | .tx_st_done = 21, | ||
179 | }; | 183 | }; |
180 | 184 | ||
181 | struct platform_device s5pc100_device_spi2 = { | 185 | struct platform_device s5pc100_device_spi2 = { |
diff --git a/arch/arm/mach-s5pv210/dev-spi.c b/arch/arm/mach-s5pv210/dev-spi.c index e3249a47e3b1..eaf9a7bff7a0 100644 --- a/arch/arm/mach-s5pv210/dev-spi.c +++ b/arch/arm/mach-s5pv210/dev-spi.c | |||
@@ -85,6 +85,7 @@ static struct s3c64xx_spi_info s5pv210_spi0_pdata = { | |||
85 | .fifo_lvl_mask = 0x1ff, | 85 | .fifo_lvl_mask = 0x1ff, |
86 | .rx_lvl_offset = 15, | 86 | .rx_lvl_offset = 15, |
87 | .high_speed = 1, | 87 | .high_speed = 1, |
88 | .tx_st_done = 25, | ||
88 | }; | 89 | }; |
89 | 90 | ||
90 | static u64 spi_dmamask = DMA_BIT_MASK(32); | 91 | static u64 spi_dmamask = DMA_BIT_MASK(32); |
@@ -129,6 +130,7 @@ static struct s3c64xx_spi_info s5pv210_spi1_pdata = { | |||
129 | .fifo_lvl_mask = 0x7f, | 130 | .fifo_lvl_mask = 0x7f, |
130 | .rx_lvl_offset = 15, | 131 | .rx_lvl_offset = 15, |
131 | .high_speed = 1, | 132 | .high_speed = 1, |
133 | .tx_st_done = 25, | ||
132 | }; | 134 | }; |
133 | 135 | ||
134 | struct platform_device s5pv210_device_spi1 = { | 136 | struct platform_device s5pv210_device_spi1 = { |
diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index 1e2aba23e0d6..ce5c2513c6ce 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c | |||
@@ -381,7 +381,7 @@ void ag5evm_sdhi1_set_pwr(struct platform_device *pdev, int state) | |||
381 | gpio_set_value(GPIO_PORT114, state); | 381 | gpio_set_value(GPIO_PORT114, state); |
382 | } | 382 | } |
383 | 383 | ||
384 | static struct sh_mobile_sdhi_info sh_sdhi1_platdata = { | 384 | static struct sh_mobile_sdhi_info sh_sdhi1_info = { |
385 | .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE, | 385 | .tmio_flags = TMIO_MMC_WRPROTECT_DISABLE, |
386 | .tmio_caps = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ, | 386 | .tmio_caps = MMC_CAP_NONREMOVABLE | MMC_CAP_SDIO_IRQ, |
387 | .tmio_ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, | 387 | .tmio_ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34, |
@@ -413,7 +413,7 @@ static struct platform_device sdhi1_device = { | |||
413 | .name = "sh_mobile_sdhi", | 413 | .name = "sh_mobile_sdhi", |
414 | .id = 1, | 414 | .id = 1, |
415 | .dev = { | 415 | .dev = { |
416 | .platform_data = &sh_sdhi1_platdata, | 416 | .platform_data = &sh_sdhi1_info, |
417 | }, | 417 | }, |
418 | .num_resources = ARRAY_SIZE(sdhi1_resources), | 418 | .num_resources = ARRAY_SIZE(sdhi1_resources), |
419 | .resource = sdhi1_resources, | 419 | .resource = sdhi1_resources, |
diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index f6b687f61c28..803bc6edfca4 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c | |||
@@ -913,7 +913,7 @@ static struct i2c_board_info imx074_info = { | |||
913 | I2C_BOARD_INFO("imx074", 0x1a), | 913 | I2C_BOARD_INFO("imx074", 0x1a), |
914 | }; | 914 | }; |
915 | 915 | ||
916 | struct soc_camera_link imx074_link = { | 916 | static struct soc_camera_link imx074_link = { |
917 | .bus_id = 0, | 917 | .bus_id = 0, |
918 | .board_info = &imx074_info, | 918 | .board_info = &imx074_info, |
919 | .i2c_adapter_id = 0, | 919 | .i2c_adapter_id = 0, |
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 7e1d37584321..3802f2afabef 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c | |||
@@ -1287,9 +1287,9 @@ static struct platform_device *mackerel_devices[] __initdata = { | |||
1287 | &nor_flash_device, | 1287 | &nor_flash_device, |
1288 | &smc911x_device, | 1288 | &smc911x_device, |
1289 | &lcdc_device, | 1289 | &lcdc_device, |
1290 | &usbhs0_device, | ||
1291 | &usb1_host_device, | 1290 | &usb1_host_device, |
1292 | &usbhs1_device, | 1291 | &usbhs1_device, |
1292 | &usbhs0_device, | ||
1293 | &leds_device, | 1293 | &leds_device, |
1294 | &fsi_device, | 1294 | &fsi_device, |
1295 | &fsi_ak4643_device, | 1295 | &fsi_ak4643_device, |
diff --git a/arch/arm/mach-ux500/board-mop500-pins.c b/arch/arm/mach-ux500/board-mop500-pins.c index fd4cf1ca5efd..70cdbd60596a 100644 --- a/arch/arm/mach-ux500/board-mop500-pins.c +++ b/arch/arm/mach-ux500/board-mop500-pins.c | |||
@@ -110,10 +110,18 @@ static pin_cfg_t mop500_pins_common[] = { | |||
110 | GPIO168_KP_O0, | 110 | GPIO168_KP_O0, |
111 | 111 | ||
112 | /* UART */ | 112 | /* UART */ |
113 | GPIO0_U0_CTSn | PIN_INPUT_PULLUP, | 113 | /* uart-0 pins gpio configuration should be |
114 | GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, | 114 | * kept intact to prevent glitch in tx line |
115 | GPIO2_U0_RXD | PIN_INPUT_PULLUP, | 115 | * when tty dev is opened. Later these pins |
116 | GPIO3_U0_TXD | PIN_OUTPUT_HIGH, | 116 | * are configured to uart mop500_pins_uart0 |
117 | * | ||
118 | * It will be replaced with uart configuration | ||
119 | * once the issue is solved. | ||
120 | */ | ||
121 | GPIO0_GPIO | PIN_INPUT_PULLUP, | ||
122 | GPIO1_GPIO | PIN_OUTPUT_HIGH, | ||
123 | GPIO2_GPIO | PIN_INPUT_PULLUP, | ||
124 | GPIO3_GPIO | PIN_OUTPUT_HIGH, | ||
117 | 125 | ||
118 | GPIO29_U2_RXD | PIN_INPUT_PULLUP, | 126 | GPIO29_U2_RXD | PIN_INPUT_PULLUP, |
119 | GPIO30_U2_TXD | PIN_OUTPUT_HIGH, | 127 | GPIO30_U2_TXD | PIN_OUTPUT_HIGH, |
diff --git a/arch/arm/mach-ux500/board-mop500.c b/arch/arm/mach-ux500/board-mop500.c index bb26f40493e6..2a08c07dec6d 100644 --- a/arch/arm/mach-ux500/board-mop500.c +++ b/arch/arm/mach-ux500/board-mop500.c | |||
@@ -27,18 +27,21 @@ | |||
27 | #include <linux/leds-lp5521.h> | 27 | #include <linux/leds-lp5521.h> |
28 | #include <linux/input.h> | 28 | #include <linux/input.h> |
29 | #include <linux/gpio_keys.h> | 29 | #include <linux/gpio_keys.h> |
30 | #include <linux/delay.h> | ||
30 | 31 | ||
31 | #include <asm/mach-types.h> | 32 | #include <asm/mach-types.h> |
32 | #include <asm/mach/arch.h> | 33 | #include <asm/mach/arch.h> |
33 | 34 | ||
34 | #include <plat/i2c.h> | 35 | #include <plat/i2c.h> |
35 | #include <plat/ste_dma40.h> | 36 | #include <plat/ste_dma40.h> |
37 | #include <plat/pincfg.h> | ||
36 | 38 | ||
37 | #include <mach/hardware.h> | 39 | #include <mach/hardware.h> |
38 | #include <mach/setup.h> | 40 | #include <mach/setup.h> |
39 | #include <mach/devices.h> | 41 | #include <mach/devices.h> |
40 | #include <mach/irqs.h> | 42 | #include <mach/irqs.h> |
41 | 43 | ||
44 | #include "pins-db8500.h" | ||
42 | #include "ste-dma40-db8500.h" | 45 | #include "ste-dma40-db8500.h" |
43 | #include "devices-db8500.h" | 46 | #include "devices-db8500.h" |
44 | #include "board-mop500.h" | 47 | #include "board-mop500.h" |
@@ -393,12 +396,63 @@ static struct stedma40_chan_cfg uart2_dma_cfg_tx = { | |||
393 | }; | 396 | }; |
394 | #endif | 397 | #endif |
395 | 398 | ||
399 | |||
400 | static pin_cfg_t mop500_pins_uart0[] = { | ||
401 | GPIO0_U0_CTSn | PIN_INPUT_PULLUP, | ||
402 | GPIO1_U0_RTSn | PIN_OUTPUT_HIGH, | ||
403 | GPIO2_U0_RXD | PIN_INPUT_PULLUP, | ||
404 | GPIO3_U0_TXD | PIN_OUTPUT_HIGH, | ||
405 | }; | ||
406 | |||
407 | #define PRCC_K_SOFTRST_SET 0x18 | ||
408 | #define PRCC_K_SOFTRST_CLEAR 0x1C | ||
409 | static void ux500_uart0_reset(void) | ||
410 | { | ||
411 | void __iomem *prcc_rst_set, *prcc_rst_clr; | ||
412 | |||
413 | prcc_rst_set = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE + | ||
414 | PRCC_K_SOFTRST_SET); | ||
415 | prcc_rst_clr = (void __iomem *)IO_ADDRESS(U8500_CLKRST1_BASE + | ||
416 | PRCC_K_SOFTRST_CLEAR); | ||
417 | |||
418 | /* Activate soft reset PRCC_K_SOFTRST_CLEAR */ | ||
419 | writel((readl(prcc_rst_clr) | 0x1), prcc_rst_clr); | ||
420 | udelay(1); | ||
421 | |||
422 | /* Release soft reset PRCC_K_SOFTRST_SET */ | ||
423 | writel((readl(prcc_rst_set) | 0x1), prcc_rst_set); | ||
424 | udelay(1); | ||
425 | } | ||
426 | |||
427 | static void ux500_uart0_init(void) | ||
428 | { | ||
429 | int ret; | ||
430 | |||
431 | ret = nmk_config_pins(mop500_pins_uart0, | ||
432 | ARRAY_SIZE(mop500_pins_uart0)); | ||
433 | if (ret < 0) | ||
434 | pr_err("pl011: uart pins_enable failed\n"); | ||
435 | } | ||
436 | |||
437 | static void ux500_uart0_exit(void) | ||
438 | { | ||
439 | int ret; | ||
440 | |||
441 | ret = nmk_config_pins_sleep(mop500_pins_uart0, | ||
442 | ARRAY_SIZE(mop500_pins_uart0)); | ||
443 | if (ret < 0) | ||
444 | pr_err("pl011: uart pins_disable failed\n"); | ||
445 | } | ||
446 | |||
396 | static struct amba_pl011_data uart0_plat = { | 447 | static struct amba_pl011_data uart0_plat = { |
397 | #ifdef CONFIG_STE_DMA40 | 448 | #ifdef CONFIG_STE_DMA40 |
398 | .dma_filter = stedma40_filter, | 449 | .dma_filter = stedma40_filter, |
399 | .dma_rx_param = &uart0_dma_cfg_rx, | 450 | .dma_rx_param = &uart0_dma_cfg_rx, |
400 | .dma_tx_param = &uart0_dma_cfg_tx, | 451 | .dma_tx_param = &uart0_dma_cfg_tx, |
401 | #endif | 452 | #endif |
453 | .init = ux500_uart0_init, | ||
454 | .exit = ux500_uart0_exit, | ||
455 | .reset = ux500_uart0_reset, | ||
402 | }; | 456 | }; |
403 | 457 | ||
404 | static struct amba_pl011_data uart1_plat = { | 458 | static struct amba_pl011_data uart1_plat = { |
diff --git a/arch/arm/mach-vt8500/irq.c b/arch/arm/mach-vt8500/irq.c index 245140c0df10..642de0408f25 100644 --- a/arch/arm/mach-vt8500/irq.c +++ b/arch/arm/mach-vt8500/irq.c | |||
@@ -39,9 +39,10 @@ | |||
39 | static void __iomem *ic_regbase; | 39 | static void __iomem *ic_regbase; |
40 | static void __iomem *sic_regbase; | 40 | static void __iomem *sic_regbase; |
41 | 41 | ||
42 | static void vt8500_irq_mask(unsigned int irq) | 42 | static void vt8500_irq_mask(struct irq_data *d) |
43 | { | 43 | { |
44 | void __iomem *base = ic_regbase; | 44 | void __iomem *base = ic_regbase; |
45 | unsigned irq = d->irq; | ||
45 | u8 edge; | 46 | u8 edge; |
46 | 47 | ||
47 | if (irq >= 64) { | 48 | if (irq >= 64) { |
@@ -64,9 +65,10 @@ static void vt8500_irq_mask(unsigned int irq) | |||
64 | } | 65 | } |
65 | } | 66 | } |
66 | 67 | ||
67 | static void vt8500_irq_unmask(unsigned int irq) | 68 | static void vt8500_irq_unmask(struct irq_data *d) |
68 | { | 69 | { |
69 | void __iomem *base = ic_regbase; | 70 | void __iomem *base = ic_regbase; |
71 | unsigned irq = d->irq; | ||
70 | u8 dctr; | 72 | u8 dctr; |
71 | 73 | ||
72 | if (irq >= 64) { | 74 | if (irq >= 64) { |
@@ -78,10 +80,11 @@ static void vt8500_irq_unmask(unsigned int irq) | |||
78 | writeb(dctr, base + VT8500_IC_DCTR + irq); | 80 | writeb(dctr, base + VT8500_IC_DCTR + irq); |
79 | } | 81 | } |
80 | 82 | ||
81 | static int vt8500_irq_set_type(unsigned int irq, unsigned int flow_type) | 83 | static int vt8500_irq_set_type(struct irq_data *d, unsigned int flow_type) |
82 | { | 84 | { |
83 | void __iomem *base = ic_regbase; | 85 | void __iomem *base = ic_regbase; |
84 | unsigned int orig_irq = irq; | 86 | unsigned irq = d->irq; |
87 | unsigned orig_irq = irq; | ||
85 | u8 dctr; | 88 | u8 dctr; |
86 | 89 | ||
87 | if (irq >= 64) { | 90 | if (irq >= 64) { |
@@ -114,11 +117,11 @@ static int vt8500_irq_set_type(unsigned int irq, unsigned int flow_type) | |||
114 | } | 117 | } |
115 | 118 | ||
116 | static struct irq_chip vt8500_irq_chip = { | 119 | static struct irq_chip vt8500_irq_chip = { |
117 | .name = "vt8500", | 120 | .name = "vt8500", |
118 | .ack = vt8500_irq_mask, | 121 | .irq_ack = vt8500_irq_mask, |
119 | .mask = vt8500_irq_mask, | 122 | .irq_mask = vt8500_irq_mask, |
120 | .unmask = vt8500_irq_unmask, | 123 | .irq_unmask = vt8500_irq_unmask, |
121 | .set_type = vt8500_irq_set_type, | 124 | .irq_set_type = vt8500_irq_set_type, |
122 | }; | 125 | }; |
123 | 126 | ||
124 | void __init vt8500_init_irq(void) | 127 | void __init vt8500_init_irq(void) |
diff --git a/arch/arm/mm/cache-l2x0.c b/arch/arm/mm/cache-l2x0.c index ef59099a5463..44c086710d2b 100644 --- a/arch/arm/mm/cache-l2x0.c +++ b/arch/arm/mm/cache-l2x0.c | |||
@@ -120,17 +120,22 @@ static void l2x0_cache_sync(void) | |||
120 | spin_unlock_irqrestore(&l2x0_lock, flags); | 120 | spin_unlock_irqrestore(&l2x0_lock, flags); |
121 | } | 121 | } |
122 | 122 | ||
123 | static void l2x0_flush_all(void) | 123 | static void __l2x0_flush_all(void) |
124 | { | 124 | { |
125 | unsigned long flags; | ||
126 | |||
127 | /* clean all ways */ | ||
128 | spin_lock_irqsave(&l2x0_lock, flags); | ||
129 | debug_writel(0x03); | 125 | debug_writel(0x03); |
130 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); | 126 | writel_relaxed(l2x0_way_mask, l2x0_base + L2X0_CLEAN_INV_WAY); |
131 | cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); | 127 | cache_wait_way(l2x0_base + L2X0_CLEAN_INV_WAY, l2x0_way_mask); |
132 | cache_sync(); | 128 | cache_sync(); |
133 | debug_writel(0x00); | 129 | debug_writel(0x00); |
130 | } | ||
131 | |||
132 | static void l2x0_flush_all(void) | ||
133 | { | ||
134 | unsigned long flags; | ||
135 | |||
136 | /* clean all ways */ | ||
137 | spin_lock_irqsave(&l2x0_lock, flags); | ||
138 | __l2x0_flush_all(); | ||
134 | spin_unlock_irqrestore(&l2x0_lock, flags); | 139 | spin_unlock_irqrestore(&l2x0_lock, flags); |
135 | } | 140 | } |
136 | 141 | ||
@@ -266,7 +271,9 @@ static void l2x0_disable(void) | |||
266 | unsigned long flags; | 271 | unsigned long flags; |
267 | 272 | ||
268 | spin_lock_irqsave(&l2x0_lock, flags); | 273 | spin_lock_irqsave(&l2x0_lock, flags); |
269 | writel(0, l2x0_base + L2X0_CTRL); | 274 | __l2x0_flush_all(); |
275 | writel_relaxed(0, l2x0_base + L2X0_CTRL); | ||
276 | dsb(); | ||
270 | spin_unlock_irqrestore(&l2x0_lock, flags); | 277 | spin_unlock_irqrestore(&l2x0_lock, flags); |
271 | } | 278 | } |
272 | 279 | ||
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c index 9d9e736c2b4f..594d677b92c8 100644 --- a/arch/arm/mm/mmu.c +++ b/arch/arm/mm/mmu.c | |||
@@ -759,7 +759,7 @@ early_param("vmalloc", early_vmalloc); | |||
759 | 759 | ||
760 | static phys_addr_t lowmem_limit __initdata = 0; | 760 | static phys_addr_t lowmem_limit __initdata = 0; |
761 | 761 | ||
762 | static void __init sanity_check_meminfo(void) | 762 | void __init sanity_check_meminfo(void) |
763 | { | 763 | { |
764 | int i, j, highmem = 0; | 764 | int i, j, highmem = 0; |
765 | 765 | ||
@@ -1032,8 +1032,9 @@ void __init paging_init(struct machine_desc *mdesc) | |||
1032 | { | 1032 | { |
1033 | void *zero_page; | 1033 | void *zero_page; |
1034 | 1034 | ||
1035 | memblock_set_current_limit(lowmem_limit); | ||
1036 | |||
1035 | build_mem_type_table(); | 1037 | build_mem_type_table(); |
1036 | sanity_check_meminfo(); | ||
1037 | prepare_page_table(); | 1038 | prepare_page_table(); |
1038 | map_lowmem(); | 1039 | map_lowmem(); |
1039 | devicemaps_init(mdesc); | 1040 | devicemaps_init(mdesc); |
diff --git a/arch/arm/mm/nommu.c b/arch/arm/mm/nommu.c index 687d02319a41..941a98c9e8aa 100644 --- a/arch/arm/mm/nommu.c +++ b/arch/arm/mm/nommu.c | |||
@@ -27,6 +27,10 @@ void __init arm_mm_memblock_reserve(void) | |||
27 | memblock_reserve(CONFIG_VECTORS_BASE, PAGE_SIZE); | 27 | memblock_reserve(CONFIG_VECTORS_BASE, PAGE_SIZE); |
28 | } | 28 | } |
29 | 29 | ||
30 | void __init sanity_check_meminfo(void) | ||
31 | { | ||
32 | } | ||
33 | |||
30 | /* | 34 | /* |
31 | * paging_init() sets up the page tables, initialises the zone memory | 35 | * paging_init() sets up the page tables, initialises the zone memory |
32 | * maps, and sets up the zero page, bad page and bad page tables. | 36 | * maps, and sets up the zero page, bad page and bad page tables. |
diff --git a/arch/arm/plat-s3c24xx/dma.c b/arch/arm/plat-s3c24xx/dma.c index 2abf9660bc6c..a79a8ccd25f6 100644 --- a/arch/arm/plat-s3c24xx/dma.c +++ b/arch/arm/plat-s3c24xx/dma.c | |||
@@ -1027,17 +1027,13 @@ int s3c2410_dma_config(unsigned int channel, | |||
1027 | struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); | 1027 | struct s3c2410_dma_chan *chan = s3c_dma_lookup_channel(channel); |
1028 | unsigned int dcon; | 1028 | unsigned int dcon; |
1029 | 1029 | ||
1030 | pr_debug("%s: chan=%d, xfer_unit=%d, dcon=%08x\n", | 1030 | pr_debug("%s: chan=%d, xfer_unit=%d\n", __func__, channel, xferunit); |
1031 | __func__, channel, xferunit, dcon); | ||
1032 | 1031 | ||
1033 | if (chan == NULL) | 1032 | if (chan == NULL) |
1034 | return -EINVAL; | 1033 | return -EINVAL; |
1035 | 1034 | ||
1036 | pr_debug("%s: Initial dcon is %08x\n", __func__, dcon); | ||
1037 | |||
1038 | dcon = chan->dcon & dma_sel.dcon_mask; | 1035 | dcon = chan->dcon & dma_sel.dcon_mask; |
1039 | 1036 | pr_debug("%s: dcon is %08x\n", __func__, dcon); | |
1040 | pr_debug("%s: New dcon is %08x\n", __func__, dcon); | ||
1041 | 1037 | ||
1042 | switch (chan->req_ch) { | 1038 | switch (chan->req_ch) { |
1043 | case DMACH_I2S_IN: | 1039 | case DMACH_I2S_IN: |
@@ -1235,7 +1231,7 @@ static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp) | |||
1235 | /* restore channel's hardware configuration */ | 1231 | /* restore channel's hardware configuration */ |
1236 | 1232 | ||
1237 | if (!cp->in_use) | 1233 | if (!cp->in_use) |
1238 | return 0; | 1234 | return; |
1239 | 1235 | ||
1240 | printk(KERN_INFO "dma%d: restoring configuration\n", cp->number); | 1236 | printk(KERN_INFO "dma%d: restoring configuration\n", cp->number); |
1241 | 1237 | ||
@@ -1246,8 +1242,6 @@ static void s3c2410_dma_resume_chan(struct s3c2410_dma_chan *cp) | |||
1246 | 1242 | ||
1247 | if (cp->map != NULL) | 1243 | if (cp->map != NULL) |
1248 | dma_sel.select(cp, cp->map); | 1244 | dma_sel.select(cp, cp->map); |
1249 | |||
1250 | return 0; | ||
1251 | } | 1245 | } |
1252 | 1246 | ||
1253 | static void s3c2410_dma_resume(void) | 1247 | static void s3c2410_dma_resume(void) |
diff --git a/arch/arm/plat-s5p/s5p-time.c b/arch/arm/plat-s5p/s5p-time.c index 899a8cc011ff..612934c48b0d 100644 --- a/arch/arm/plat-s5p/s5p-time.c +++ b/arch/arm/plat-s5p/s5p-time.c | |||
@@ -370,11 +370,11 @@ static void __init s5p_clocksource_init(void) | |||
370 | 370 | ||
371 | clock_rate = clk_get_rate(tin_source); | 371 | clock_rate = clk_get_rate(tin_source); |
372 | 372 | ||
373 | init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate); | ||
374 | |||
375 | s5p_time_setup(timer_source.source_id, TCNT_MAX); | 373 | s5p_time_setup(timer_source.source_id, TCNT_MAX); |
376 | s5p_time_start(timer_source.source_id, PERIODIC); | 374 | s5p_time_start(timer_source.source_id, PERIODIC); |
377 | 375 | ||
376 | init_sched_clock(&cd, s5p_update_sched_clock, 32, clock_rate); | ||
377 | |||
378 | if (clocksource_register_hz(&time_clocksource, clock_rate)) | 378 | if (clocksource_register_hz(&time_clocksource, clock_rate)) |
379 | panic("%s: can't register clocksource\n", time_clocksource.name); | 379 | panic("%s: can't register clocksource\n", time_clocksource.name); |
380 | } | 380 | } |
diff --git a/arch/arm/plat-samsung/include/plat/devs.h b/arch/arm/plat-samsung/include/plat/devs.h index 4af108ff4112..e3b31c26ac3e 100644 --- a/arch/arm/plat-samsung/include/plat/devs.h +++ b/arch/arm/plat-samsung/include/plat/devs.h | |||
@@ -12,6 +12,10 @@ | |||
12 | * it under the terms of the GNU General Public License version 2 as | 12 | * it under the terms of the GNU General Public License version 2 as |
13 | * published by the Free Software Foundation. | 13 | * published by the Free Software Foundation. |
14 | */ | 14 | */ |
15 | |||
16 | #ifndef __PLAT_DEVS_H | ||
17 | #define __PLAT_DEVS_H __FILE__ | ||
18 | |||
15 | #include <linux/platform_device.h> | 19 | #include <linux/platform_device.h> |
16 | 20 | ||
17 | struct s3c24xx_uart_resources { | 21 | struct s3c24xx_uart_resources { |
@@ -159,3 +163,5 @@ extern struct platform_device s3c_device_ac97; | |||
159 | */ | 163 | */ |
160 | extern void *s3c_set_platdata(void *pd, size_t pdsize, | 164 | extern void *s3c_set_platdata(void *pd, size_t pdsize, |
161 | struct platform_device *pdev); | 165 | struct platform_device *pdev); |
166 | |||
167 | #endif /* __PLAT_DEVS_H */ | ||
diff --git a/arch/arm/plat-samsung/include/plat/regs-serial.h b/arch/arm/plat-samsung/include/plat/regs-serial.h index c151c5f94a87..116edfe120b9 100644 --- a/arch/arm/plat-samsung/include/plat/regs-serial.h +++ b/arch/arm/plat-samsung/include/plat/regs-serial.h | |||
@@ -224,6 +224,8 @@ | |||
224 | #define S5PV210_UFSTAT_RXMASK (255<<0) | 224 | #define S5PV210_UFSTAT_RXMASK (255<<0) |
225 | #define S5PV210_UFSTAT_RXSHIFT (0) | 225 | #define S5PV210_UFSTAT_RXSHIFT (0) |
226 | 226 | ||
227 | #define NO_NEED_CHECK_CLKSRC 1 | ||
228 | |||
227 | #ifndef __ASSEMBLY__ | 229 | #ifndef __ASSEMBLY__ |
228 | 230 | ||
229 | /* struct s3c24xx_uart_clksrc | 231 | /* struct s3c24xx_uart_clksrc |
diff --git a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h index 0ffe34a21554..4c16fa3621bb 100644 --- a/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h +++ b/arch/arm/plat-samsung/include/plat/s3c64xx-spi.h | |||
@@ -39,6 +39,7 @@ struct s3c64xx_spi_csinfo { | |||
39 | * @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6 | 39 | * @fifo_lvl_mask: All tx fifo_lvl fields start at offset-6 |
40 | * @rx_lvl_offset: Depends on tx fifo_lvl field and bus number | 40 | * @rx_lvl_offset: Depends on tx fifo_lvl field and bus number |
41 | * @high_speed: If the controller supports HIGH_SPEED_EN bit | 41 | * @high_speed: If the controller supports HIGH_SPEED_EN bit |
42 | * @tx_st_done: Depends on tx fifo_lvl field | ||
42 | */ | 43 | */ |
43 | struct s3c64xx_spi_info { | 44 | struct s3c64xx_spi_info { |
44 | int src_clk_nr; | 45 | int src_clk_nr; |
@@ -53,6 +54,7 @@ struct s3c64xx_spi_info { | |||
53 | int fifo_lvl_mask; | 54 | int fifo_lvl_mask; |
54 | int rx_lvl_offset; | 55 | int rx_lvl_offset; |
55 | int high_speed; | 56 | int high_speed; |
57 | int tx_st_done; | ||
56 | }; | 58 | }; |
57 | 59 | ||
58 | /** | 60 | /** |