Commit | Line | Data |
---|---|---|
24371707 JM |
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 | ||
eaf4f33f JM |
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 | ||
3f92dfed JM |
29 | static const union decode_item t16_table_1011[] = { |
30 | /* Miscellaneous 16-bit instructions */ | |
31 | ||
32 | /* | |
33 | * If-Then, and hints | |
34 | * 1011 1111 xxxx xxxx | |
35 | */ | |
36 | ||
37 | /* YIELD 1011 1111 0001 0000 */ | |
38 | DECODE_OR (0xffff, 0xbf10), | |
39 | /* SEV 1011 1111 0100 0000 */ | |
40 | DECODE_EMULATE (0xffff, 0xbf40, kprobe_emulate_none), | |
41 | /* NOP 1011 1111 0000 0000 */ | |
42 | /* WFE 1011 1111 0010 0000 */ | |
43 | /* WFI 1011 1111 0011 0000 */ | |
44 | DECODE_SIMULATE (0xffcf, 0xbf00, kprobe_simulate_nop), | |
45 | /* Unassigned hints 1011 1111 xxxx 0000 */ | |
46 | DECODE_REJECT (0xff0f, 0xbf00), | |
47 | ||
48 | DECODE_END | |
49 | }; | |
50 | ||
51 | const union decode_item kprobe_decode_thumb16_table[] = { | |
52 | ||
53 | /* | |
54 | * Miscellaneous 16-bit instructions | |
55 | * 1011 xxxx xxxx xxxx | |
56 | */ | |
57 | DECODE_TABLE (0xf000, 0xb000, t16_table_1011), | |
58 | ||
59 | DECODE_END | |
60 | }; | |
61 | ||
eaf4f33f JM |
62 | static unsigned long __kprobes thumb_check_cc(unsigned long cpsr) |
63 | { | |
64 | if (unlikely(in_it_block(cpsr))) | |
65 | return kprobe_condition_checks[current_cond(cpsr)](cpsr); | |
66 | return true; | |
67 | } | |
68 | ||
c6a7d97d JM |
69 | static void __kprobes thumb16_singlestep(struct kprobe *p, struct pt_regs *regs) |
70 | { | |
71 | regs->ARM_pc += 2; | |
72 | p->ainsn.insn_handler(p, regs); | |
73 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | |
74 | } | |
75 | ||
76 | static void __kprobes thumb32_singlestep(struct kprobe *p, struct pt_regs *regs) | |
77 | { | |
78 | regs->ARM_pc += 4; | |
79 | p->ainsn.insn_handler(p, regs); | |
80 | regs->ARM_cpsr = it_advance(regs->ARM_cpsr); | |
81 | } | |
82 | ||
24371707 JM |
83 | enum kprobe_insn __kprobes |
84 | thumb16_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
85 | { | |
c6a7d97d | 86 | asi->insn_singlestep = thumb16_singlestep; |
eaf4f33f | 87 | asi->insn_check_cc = thumb_check_cc; |
3f92dfed | 88 | return kprobe_decode_insn(insn, asi, kprobe_decode_thumb16_table, true); |
24371707 JM |
89 | } |
90 | ||
91 | enum kprobe_insn __kprobes | |
92 | thumb32_kprobe_decode_insn(kprobe_opcode_t insn, struct arch_specific_insn *asi) | |
93 | { | |
c6a7d97d | 94 | asi->insn_singlestep = thumb32_singlestep; |
eaf4f33f | 95 | asi->insn_check_cc = thumb_check_cc; |
24371707 JM |
96 | return INSN_REJECTED; |
97 | } |