Commit | Line | Data |
---|---|---|
b11a64a4 JL |
1 | /* |
2 | * Copyright (C) 2013 Huawei Ltd. | |
3 | * Author: Jiang Liu <liuj97@gmail.com> | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License version 2 as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * This program is distributed in the hope that it will be useful, | |
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | * GNU General Public License for more details. | |
13 | * | |
14 | * You should have received a copy of the GNU General Public License | |
15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
16 | */ | |
17 | #include <linux/compiler.h> | |
18 | #include <linux/kernel.h> | |
19 | #include <asm/insn.h> | |
20 | ||
21 | static int aarch64_insn_encoding_class[] = { | |
22 | AARCH64_INSN_CLS_UNKNOWN, | |
23 | AARCH64_INSN_CLS_UNKNOWN, | |
24 | AARCH64_INSN_CLS_UNKNOWN, | |
25 | AARCH64_INSN_CLS_UNKNOWN, | |
26 | AARCH64_INSN_CLS_LDST, | |
27 | AARCH64_INSN_CLS_DP_REG, | |
28 | AARCH64_INSN_CLS_LDST, | |
29 | AARCH64_INSN_CLS_DP_FPSIMD, | |
30 | AARCH64_INSN_CLS_DP_IMM, | |
31 | AARCH64_INSN_CLS_DP_IMM, | |
32 | AARCH64_INSN_CLS_BR_SYS, | |
33 | AARCH64_INSN_CLS_BR_SYS, | |
34 | AARCH64_INSN_CLS_LDST, | |
35 | AARCH64_INSN_CLS_DP_REG, | |
36 | AARCH64_INSN_CLS_LDST, | |
37 | AARCH64_INSN_CLS_DP_FPSIMD, | |
38 | }; | |
39 | ||
40 | enum aarch64_insn_encoding_class __kprobes aarch64_get_insn_class(u32 insn) | |
41 | { | |
42 | return aarch64_insn_encoding_class[(insn >> 25) & 0xf]; | |
43 | } | |
44 | ||
45 | /* NOP is an alias of HINT */ | |
46 | bool __kprobes aarch64_insn_is_nop(u32 insn) | |
47 | { | |
48 | if (!aarch64_insn_is_hint(insn)) | |
49 | return false; | |
50 | ||
51 | switch (insn & 0xFE0) { | |
52 | case AARCH64_INSN_HINT_YIELD: | |
53 | case AARCH64_INSN_HINT_WFE: | |
54 | case AARCH64_INSN_HINT_WFI: | |
55 | case AARCH64_INSN_HINT_SEV: | |
56 | case AARCH64_INSN_HINT_SEVL: | |
57 | return false; | |
58 | default: | |
59 | return true; | |
60 | } | |
61 | } | |
62 | ||
63 | static bool __kprobes __aarch64_insn_hotpatch_safe(u32 insn) | |
64 | { | |
65 | if (aarch64_get_insn_class(insn) != AARCH64_INSN_CLS_BR_SYS) | |
66 | return false; | |
67 | ||
68 | return aarch64_insn_is_b(insn) || | |
69 | aarch64_insn_is_bl(insn) || | |
70 | aarch64_insn_is_svc(insn) || | |
71 | aarch64_insn_is_hvc(insn) || | |
72 | aarch64_insn_is_smc(insn) || | |
73 | aarch64_insn_is_brk(insn) || | |
74 | aarch64_insn_is_nop(insn); | |
75 | } | |
76 | ||
77 | /* | |
78 | * ARM Architecture Reference Manual for ARMv8 Profile-A, Issue A.a | |
79 | * Section B2.6.5 "Concurrent modification and execution of instructions": | |
80 | * Concurrent modification and execution of instructions can lead to the | |
81 | * resulting instruction performing any behavior that can be achieved by | |
82 | * executing any sequence of instructions that can be executed from the | |
83 | * same Exception level, except where the instruction before modification | |
84 | * and the instruction after modification is a B, BL, NOP, BKPT, SVC, HVC, | |
85 | * or SMC instruction. | |
86 | */ | |
87 | bool __kprobes aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn) | |
88 | { | |
89 | return __aarch64_insn_hotpatch_safe(old_insn) && | |
90 | __aarch64_insn_hotpatch_safe(new_insn); | |
91 | } |